GrGpu.cpp revision 02a44a488605112aa6683c9d919e13b188112ce1
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 "GrBufferAllocPool.h"
13#include "GrContext.h"
14#include "GrDrawTargetCaps.h"
15#include "GrGpuResourcePriv.h"
16#include "GrIndexBuffer.h"
17#include "GrResourceCache.h"
18#include "GrStencilBuffer.h"
19#include "GrVertexBuffer.h"
20
21////////////////////////////////////////////////////////////////////////////////
22
23GrGpu::GrGpu(GrContext* context)
24    : fResetTimestamp(kExpiredTimestamp+1)
25    , fResetBits(kAll_GrBackendState)
26    , fQuadIndexBuffer(NULL)
27    , fContext(context) {
28}
29
30GrGpu::~GrGpu() {
31    SkSafeSetNull(fQuadIndexBuffer);
32}
33
34void GrGpu::contextAbandoned() {}
35
36////////////////////////////////////////////////////////////////////////////////
37
38GrTexture* GrGpu::createTexture(const GrSurfaceDesc& desc, bool budgeted,
39                                const void* srcData, size_t rowBytes) {
40    if (!this->caps()->isConfigTexturable(desc.fConfig)) {
41        return NULL;
42    }
43
44    bool isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
45    if (isRT && !this->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
46        return NULL;
47    }
48
49    GrTexture *tex = NULL;
50    if (GrPixelConfigIsCompressed(desc.fConfig)) {
51        // We shouldn't be rendering into this
52        SkASSERT((desc.fFlags & kRenderTarget_GrSurfaceFlag) == 0);
53
54        if (!this->caps()->npotTextureTileSupport() &&
55            (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) {
56            return NULL;
57        }
58
59        this->handleDirtyContext();
60        tex = this->onCreateCompressedTexture(desc, budgeted, srcData);
61    } else {
62        this->handleDirtyContext();
63        tex = this->onCreateTexture(desc, budgeted, srcData, rowBytes);
64        if (tex &&
65            (kRenderTarget_GrSurfaceFlag & desc.fFlags) &&
66            !(kNoStencil_GrSurfaceFlag & desc.fFlags)) {
67            SkASSERT(tex->asRenderTarget());
68            // TODO: defer this and attach dynamically
69            if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) {
70                tex->unref();
71                return NULL;
72            }
73        }
74    }
75    if (!this->caps()->reuseScratchTextures() && !isRT) {
76        tex->resourcePriv().removeScratchKey();
77    }
78    if (tex) {
79        fStats.incTextureCreates();
80        if (srcData) {
81            fStats.incTextureUploads();
82        }
83    }
84    return tex;
85}
86
87bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
88    SkASSERT(NULL == rt->getStencilBuffer());
89    GrUniqueKey sbKey;
90    GrStencilBuffer::ComputeSharedStencilBufferKey(rt->width(), rt->height(), rt->numSamples(),
91                                                   &sbKey);
92    SkAutoTUnref<GrStencilBuffer> sb(static_cast<GrStencilBuffer*>(
93        this->getContext()->getResourceCache()->findAndRefUniqueResource(sbKey)));
94    if (sb) {
95        rt->setStencilBuffer(sb);
96        bool attached = this->attachStencilBufferToRenderTarget(sb, rt);
97        if (!attached) {
98            rt->setStencilBuffer(NULL);
99        }
100        return attached;
101    }
102    if (this->createStencilBufferForRenderTarget(rt, rt->width(), rt->height())) {
103        // Right now we're clearing the stencil buffer here after it is
104        // attached to an RT for the first time. When we start matching
105        // stencil buffers with smaller color targets this will no longer
106        // be correct because it won't be guaranteed to clear the entire
107        // sb.
108        // We used to clear down in the GL subclass using a special purpose
109        // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
110        // FBO status.
111        this->clearStencil(rt);
112        rt->getStencilBuffer()->resourcePriv().setUniqueKey(sbKey);
113        return true;
114    } else {
115        return false;
116    }
117}
118
119GrTexture* GrGpu::wrapBackendTexture(const GrBackendTextureDesc& desc) {
120    this->handleDirtyContext();
121    GrTexture* tex = this->onWrapBackendTexture(desc);
122    if (NULL == tex) {
123        return NULL;
124    }
125    // TODO: defer this and attach dynamically
126    GrRenderTarget* tgt = tex->asRenderTarget();
127    if (tgt && !this->attachStencilBufferToRenderTarget(tgt)) {
128        tex->unref();
129        return NULL;
130    } else {
131        return tex;
132    }
133}
134
135GrRenderTarget* GrGpu::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
136    this->handleDirtyContext();
137    return this->onWrapBackendRenderTarget(desc);
138}
139
140GrVertexBuffer* GrGpu::createVertexBuffer(size_t size, bool dynamic) {
141    this->handleDirtyContext();
142    return this->onCreateVertexBuffer(size, dynamic);
143}
144
145GrIndexBuffer* GrGpu::createIndexBuffer(size_t size, bool dynamic) {
146    this->handleDirtyContext();
147    return this->onCreateIndexBuffer(size, dynamic);
148}
149
150GrIndexBuffer* GrGpu::createInstancedIndexBuffer(const uint16_t* pattern,
151                                                 int patternSize,
152                                                 int reps,
153                                                 int vertCount,
154                                                 bool isDynamic) {
155    size_t bufferSize = patternSize * reps * sizeof(uint16_t);
156    GrGpu* me = const_cast<GrGpu*>(this);
157    GrIndexBuffer* buffer = me->createIndexBuffer(bufferSize, isDynamic);
158    if (buffer) {
159        uint16_t* data = (uint16_t*) buffer->map();
160        bool useTempData = (NULL == data);
161        if (useTempData) {
162            data = SkNEW_ARRAY(uint16_t, reps * patternSize);
163        }
164        for (int i = 0; i < reps; ++i) {
165            int baseIdx = i * patternSize;
166            uint16_t baseVert = (uint16_t)(i * vertCount);
167            for (int j = 0; j < patternSize; ++j) {
168                data[baseIdx+j] = baseVert + pattern[j];
169            }
170        }
171        if (useTempData) {
172            if (!buffer->updateData(data, bufferSize)) {
173                SkFAIL("Can't get indices into buffer!");
174            }
175            SkDELETE_ARRAY(data);
176        } else {
177            buffer->unmap();
178        }
179    }
180    return buffer;
181}
182
183void GrGpu::clear(const SkIRect* rect,
184                  GrColor color,
185                  bool canIgnoreRect,
186                  GrRenderTarget* renderTarget) {
187    SkASSERT(renderTarget);
188    this->handleDirtyContext();
189    this->onClear(renderTarget, rect, color, canIgnoreRect);
190}
191
192void GrGpu::clearStencilClip(const SkIRect& rect,
193                             bool insideClip,
194                             GrRenderTarget* renderTarget) {
195    SkASSERT(renderTarget);
196    this->handleDirtyContext();
197    this->onClearStencilClip(renderTarget, rect, insideClip);
198}
199
200bool GrGpu::readPixels(GrRenderTarget* target,
201                       int left, int top, int width, int height,
202                       GrPixelConfig config, void* buffer,
203                       size_t rowBytes) {
204    this->handleDirtyContext();
205    return this->onReadPixels(target, left, top, width, height,
206                              config, buffer, rowBytes);
207}
208
209bool GrGpu::writeTexturePixels(GrTexture* texture,
210                               int left, int top, int width, int height,
211                               GrPixelConfig config, const void* buffer,
212                               size_t rowBytes) {
213    this->handleDirtyContext();
214    if (this->onWriteTexturePixels(texture, left, top, width, height,
215                                   config, buffer, rowBytes)) {
216        fStats.incTextureUploads();
217        return true;
218    }
219    return false;
220}
221
222void GrGpu::resolveRenderTarget(GrRenderTarget* target) {
223    SkASSERT(target);
224    this->handleDirtyContext();
225    this->onResolveRenderTarget(target);
226}
227
228typedef GrTraceMarkerSet::Iter TMIter;
229void GrGpu::saveActiveTraceMarkers() {
230    if (this->caps()->gpuTracingSupport()) {
231        SkASSERT(0 == fStoredTraceMarkers.count());
232        fStoredTraceMarkers.addSet(fActiveTraceMarkers);
233        for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) {
234            this->removeGpuTraceMarker(&(*iter));
235        }
236    }
237}
238
239void GrGpu::restoreActiveTraceMarkers() {
240    if (this->caps()->gpuTracingSupport()) {
241        SkASSERT(0 == fActiveTraceMarkers.count());
242        for (TMIter iter = fStoredTraceMarkers.begin(); iter != fStoredTraceMarkers.end(); ++iter) {
243            this->addGpuTraceMarker(&(*iter));
244        }
245        for (TMIter iter = fActiveTraceMarkers.begin(); iter != fActiveTraceMarkers.end(); ++iter) {
246            this->fStoredTraceMarkers.remove(*iter);
247        }
248    }
249}
250
251void GrGpu::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
252    if (this->caps()->gpuTracingSupport()) {
253        SkASSERT(fGpuTraceMarkerCount >= 0);
254        this->fActiveTraceMarkers.add(*marker);
255        this->didAddGpuTraceMarker();
256        ++fGpuTraceMarkerCount;
257    }
258}
259
260void GrGpu::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
261    if (this->caps()->gpuTracingSupport()) {
262        SkASSERT(fGpuTraceMarkerCount >= 1);
263        this->fActiveTraceMarkers.remove(*marker);
264        this->didRemoveGpuTraceMarker();
265        --fGpuTraceMarkerCount;
266    }
267}
268
269////////////////////////////////////////////////////////////////////////////////
270
271static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
272
273GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
274
275static const uint16_t gQuadIndexPattern[] = {
276  0, 1, 2, 0, 2, 3
277};
278
279const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
280    if (NULL == fQuadIndexBuffer || fQuadIndexBuffer->wasDestroyed()) {
281        SkSafeUnref(fQuadIndexBuffer);
282        GrGpu* me = const_cast<GrGpu*>(this);
283        fQuadIndexBuffer = me->createInstancedIndexBuffer(gQuadIndexPattern,
284                                                          6,
285                                                          MAX_QUADS,
286                                                          4);
287    }
288
289    return fQuadIndexBuffer;
290}
291
292////////////////////////////////////////////////////////////////////////////////
293
294void GrGpu::draw(const DrawArgs& args, const GrDrawTarget::DrawInfo& info) {
295    this->handleDirtyContext();
296    this->onDraw(args, info);
297}
298
299void GrGpu::stencilPath(const GrPath* path, const StencilPathState& state) {
300    this->handleDirtyContext();
301    this->onStencilPath(path, state);
302}
303
304void GrGpu::drawPath(const DrawArgs& args,
305                     const GrPath* path,
306                     const GrStencilSettings& stencilSettings) {
307    this->handleDirtyContext();
308    this->onDrawPath(args, path, stencilSettings);
309}
310
311void GrGpu::drawPaths(const DrawArgs& args,
312                      const GrPathRange* pathRange,
313                      const void* indices,
314                      GrDrawTarget::PathIndexType indexType,
315                      const float transformValues[],
316                      GrDrawTarget::PathTransformType transformType,
317                      int count,
318                      const GrStencilSettings& stencilSettings) {
319    this->handleDirtyContext();
320    pathRange->willDrawPaths(indices, indexType, count);
321    this->onDrawPaths(args, pathRange, indices, indexType, transformValues,
322                      transformType, count, stencilSettings);
323}
324