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