1
2/*
3 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "GrGpu.h"
11
12#include "GrContext.h"
13#include "GrDrawTargetCaps.h"
14#include "GrGpuResourcePriv.h"
15#include "GrIndexBuffer.h"
16#include "GrResourceCache.h"
17#include "GrRenderTargetPriv.h"
18#include "GrStencilAttachment.h"
19#include "GrVertexBuffer.h"
20#include "GrVertices.h"
21
22GrVertices& GrVertices::operator =(const GrVertices& di) {
23    fPrimitiveType  = di.fPrimitiveType;
24    fStartVertex    = di.fStartVertex;
25    fStartIndex     = di.fStartIndex;
26    fVertexCount    = di.fVertexCount;
27    fIndexCount     = di.fIndexCount;
28
29    fInstanceCount          = di.fInstanceCount;
30    fVerticesPerInstance    = di.fVerticesPerInstance;
31    fIndicesPerInstance     = di.fIndicesPerInstance;
32    fMaxInstancesPerDraw    = di.fMaxInstancesPerDraw;
33
34    fVertexBuffer.reset(di.vertexBuffer());
35    fIndexBuffer.reset(di.indexBuffer());
36
37    return *this;
38}
39
40////////////////////////////////////////////////////////////////////////////////
41
42GrGpu::GrGpu(GrContext* context)
43    : fResetTimestamp(kExpiredTimestamp+1)
44    , fResetBits(kAll_GrBackendState)
45    , fGpuTraceMarkerCount(0)
46    , fContext(context) {
47}
48
49GrGpu::~GrGpu() {}
50
51void GrGpu::contextAbandoned() {}
52
53////////////////////////////////////////////////////////////////////////////////
54
55static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin, bool renderTarget) {
56    // By default, GrRenderTargets are GL's normal orientation so that they
57    // can be drawn to by the outside world without the client having
58    // to render upside down.
59    if (kDefault_GrSurfaceOrigin == origin) {
60        return renderTarget ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
61    } else {
62        return origin;
63    }
64}
65
66GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, bool budgeted,
67                                const void* srcData, size_t rowBytes) {
68    GrSurfaceDesc desc = origDesc;
69
70    if (!this->caps()->isConfigTexturable(desc.fConfig)) {
71        return NULL;
72    }
73
74    bool isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
75    if (isRT && !this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
76        return NULL;
77    }
78
79    // We currently not support multisampled textures
80    if (!isRT && desc.fSampleCnt > 0) {
81        return NULL;
82    }
83
84    GrTexture *tex = NULL;
85
86    if (isRT) {
87        int maxRTSize = this->caps()->maxRenderTargetSize();
88        if (desc.fWidth > maxRTSize || desc.fHeight > maxRTSize) {
89            return NULL;
90        }
91    } else {
92        int maxSize = this->caps()->maxTextureSize();
93        if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
94            return NULL;
95        }
96    }
97
98    GrGpuResource::LifeCycle lifeCycle = budgeted ? GrGpuResource::kCached_LifeCycle :
99                                                    GrGpuResource::kUncached_LifeCycle;
100
101    desc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount());
102    // Attempt to catch un- or wrongly initialized sample counts;
103    SkASSERT(desc.fSampleCnt >= 0 && desc.fSampleCnt <= 64);
104
105    desc.fOrigin = resolve_origin(desc.fOrigin, isRT);
106
107    if (GrPixelConfigIsCompressed(desc.fConfig)) {
108        // We shouldn't be rendering into this
109        SkASSERT(!isRT);
110        SkASSERT(0 == desc.fSampleCnt);
111
112        if (!this->caps()->npotTextureTileSupport() &&
113            (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) {
114            return NULL;
115        }
116
117        this->handleDirtyContext();
118        tex = this->onCreateCompressedTexture(desc, lifeCycle, srcData);
119    } else {
120        this->handleDirtyContext();
121        tex = this->onCreateTexture(desc, lifeCycle, srcData, rowBytes);
122    }
123    if (!this->caps()->reuseScratchTextures() && !isRT) {
124        tex->resourcePriv().removeScratchKey();
125    }
126    if (tex) {
127        fStats.incTextureCreates();
128        if (srcData) {
129            fStats.incTextureUploads();
130        }
131    }
132    return tex;
133}
134
135bool GrGpu::attachStencilAttachmentToRenderTarget(GrRenderTarget* rt) {
136    SkASSERT(NULL == rt->renderTargetPriv().getStencilAttachment());
137    GrUniqueKey sbKey;
138
139    int width = rt->width();
140    int height = rt->height();
141#if 0
142    if (this->caps()->oversizedStencilSupport()) {
143        width  = SkNextPow2(width);
144        height = SkNextPow2(height);
145    }
146#endif
147
148    GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height, rt->numSamples(), &sbKey);
149    SkAutoTUnref<GrStencilAttachment> sb(static_cast<GrStencilAttachment*>(
150        this->getContext()->getResourceCache()->findAndRefUniqueResource(sbKey)));
151    if (sb) {
152        if (this->attachStencilAttachmentToRenderTarget(sb, rt)) {
153            rt->renderTargetPriv().didAttachStencilAttachment(sb);
154            return true;
155        }
156        return false;
157    }
158    if (this->createStencilAttachmentForRenderTarget(rt, width, height)) {
159        // Right now we're clearing the stencil buffer here after it is
160        // attached to an RT for the first time. When we start matching
161        // stencil buffers with smaller color targets this will no longer
162        // be correct because it won't be guaranteed to clear the entire
163        // sb.
164        // We used to clear down in the GL subclass using a special purpose
165        // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
166        // FBO status.
167        this->clearStencil(rt);
168        GrStencilAttachment* sb = rt->renderTargetPriv().getStencilAttachment();
169        sb->resourcePriv().setUniqueKey(sbKey);
170        return true;
171    } else {
172        return false;
173    }
174}
175
176GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc) {
177    this->handleDirtyContext();
178    GrTexture* tex = this->onWrapBackendTexture(desc);
179    if (NULL == tex) {
180        return NULL;
181    }
182    // TODO: defer this and attach dynamically
183    GrRenderTarget* tgt = tex->asRenderTarget();
184    if (tgt && !this->attachStencilAttachmentToRenderTarget(tgt)) {
185        tex->unref();
186        return NULL;
187    } else {
188        return tex;
189    }
190}
191
192GrRenderTarget* GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
193    this->handleDirtyContext();
194    return this->onWrapBackendRenderTarget(desc);
195}
196
197GrVertexBuffer* GrGpu::createVertexBuffer(size_t size, bool dynamic) {
198    this->handleDirtyContext();
199    return this->onCreateVertexBuffer(size, dynamic);
200}
201
202GrIndexBuffer* GrGpu::createIndexBuffer(size_t size, bool dynamic) {
203    this->handleDirtyContext();
204    return this->onCreateIndexBuffer(size, dynamic);
205}
206
207void GrGpu::clear(const SkIRect* rect,
208                  GrColor color,
209                  bool canIgnoreRect,
210                  GrRenderTarget* renderTarget) {
211    SkASSERT(renderTarget);
212    this->handleDirtyContext();
213    this->onClear(renderTarget, rect, color, canIgnoreRect);
214}
215
216void GrGpu::clearStencilClip(const SkIRect& rect,
217                             bool insideClip,
218                             GrRenderTarget* renderTarget) {
219    SkASSERT(renderTarget);
220    this->handleDirtyContext();
221    this->onClearStencilClip(renderTarget, rect, insideClip);
222}
223
224bool GrGpu::readPixels(GrRenderTarget* target,
225                       int left, int top, int width, int height,
226                       GrPixelConfig config, void* buffer,
227                       size_t rowBytes) {
228    this->handleDirtyContext();
229    return this->onReadPixels(target, left, top, width, height,
230                              config, buffer, rowBytes);
231}
232
233bool GrGpu::writeTexturePixels(GrTexture* texture,
234                               int left, int top, int width, int height,
235                               GrPixelConfig config, const void* buffer,
236                               size_t rowBytes) {
237    this->handleDirtyContext();
238    if (this->onWriteTexturePixels(texture, left, top, width, height,
239                                   config, buffer, rowBytes)) {
240        fStats.incTextureUploads();
241        return true;
242    }
243    return false;
244}
245
246void GrGpu::resolveRenderTarget(GrRenderTarget* target) {
247    SkASSERT(target);
248    this->handleDirtyContext();
249    this->onResolveRenderTarget(target);
250}
251
252typedef GrTraceMarkerSet::Iter TMIter;
253void GrGpu::saveActiveTraceMarkers() {
254    if (this->caps()->gpuTracingSupport()) {
255        SkASSERT(0 == fStoredTraceMarkers.count());
256        fStoredTraceMarkers.addSet(fActiveTraceMarkers);
257        for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) {
258            this->removeGpuTraceMarker(&(*iter));
259        }
260    }
261}
262
263void GrGpu::restoreActiveTraceMarkers() {
264    if (this->caps()->gpuTracingSupport()) {
265        SkASSERT(0 == fActiveTraceMarkers.count());
266        for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) {
267            this->addGpuTraceMarker(&(*iter));
268        }
269        for (TMIter iter = fActiveTraceMarkers.begin(); iter != fActiveTraceMarkers.end(); ++iter) {
270            this->fStoredTraceMarkers.remove(*iter);
271        }
272    }
273}
274
275void GrGpu::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
276    if (this->caps()->gpuTracingSupport()) {
277        SkASSERT(fGpuTraceMarkerCount >= 0);
278        this->fActiveTraceMarkers.add(*marker);
279        this->didAddGpuTraceMarker();
280        ++fGpuTraceMarkerCount;
281    }
282}
283
284void GrGpu::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
285    if (this->caps()->gpuTracingSupport()) {
286        SkASSERT(fGpuTraceMarkerCount >= 1);
287        this->fActiveTraceMarkers.remove(*marker);
288        this->didRemoveGpuTraceMarker();
289        --fGpuTraceMarkerCount;
290    }
291}
292
293////////////////////////////////////////////////////////////////////////////////
294
295void GrGpu::draw(const DrawArgs& args, const GrVertices& vertices) {
296    this->handleDirtyContext();
297    GrVertices::Iterator iter;
298    const GrNonInstancedVertices* verts = iter.init(vertices);
299    do {
300        this->onDraw(args, *verts);
301    } while ((verts = iter.next()));
302}
303
304void GrGpu::stencilPath(const GrPath* path, const StencilPathState& state) {
305    this->handleDirtyContext();
306    this->onStencilPath(path, state);
307}
308
309void GrGpu::drawPath(const DrawArgs& args,
310                     const GrPath* path,
311                     const GrStencilSettings& stencilSettings) {
312    this->handleDirtyContext();
313    this->onDrawPath(args, path, stencilSettings);
314}
315
316void GrGpu::drawPaths(const DrawArgs& args,
317                      const GrPathRange* pathRange,
318                      const void* indices,
319                      GrDrawTarget::PathIndexType indexType,
320                      const float transformValues[],
321                      GrDrawTarget::PathTransformType transformType,
322                      int count,
323                      const GrStencilSettings& stencilSettings) {
324    this->handleDirtyContext();
325    pathRange->willDrawPaths(indices, indexType, count);
326    this->onDrawPaths(args, pathRange, indices, indexType, transformValues,
327                      transformType, count, stencilSettings);
328}
329