blob: 4672cff3f4e0ac5502566247118a2b2e256538ae [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@google.comac10a2d2010-12-22 21:39:39 +000010#include "GrGpu.h"
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +000011#include "GrBufferAllocPool.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000012#include "GrClipIterator.h"
13#include "GrIndexBuffer.h"
bsalomon@google.com4043ae22011-08-02 14:19:11 +000014#include "GrPathRenderer.h"
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +000015#include "GrGLStencilBuffer.h"
16#include "GrVertexBuffer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000017
18// probably makes no sense for this to be less than a page
bsalomon@google.comee435122011-07-01 14:57:55 +000019static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
20static const int VERTEX_POOL_VB_COUNT = 4;
bsalomon@google.com25fd36c2011-07-06 17:41:08 +000021static const size_t INDEX_POOL_IB_SIZE = 1 << 16;
22static const int INDEX_POOL_IB_COUNT = 4;
reed@google.comac10a2d2010-12-22 21:39:39 +000023
bsalomon@google.comd302f142011-03-03 13:54:13 +000024////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000025
26extern void gr_run_unittests();
27
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000028#define DEBUG_INVAL_BUFFER 0xdeadcafe
29#define DEBUG_INVAL_START_IDX -1
30
bsalomon@google.com8fe72472011-03-30 21:26:44 +000031GrGpu::GrGpu()
32 : f8bitPaletteSupport(false)
bsalomon@google.com669fdc42011-04-05 17:08:27 +000033 , fContext(NULL)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000034 , fVertexPool(NULL)
35 , fIndexPool(NULL)
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000036 , fVertexPoolUseCnt(0)
37 , fIndexPoolUseCnt(0)
38 , fGeomPoolStateStack(&fGeoSrcStateStackStorage)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000039 , fQuadIndexBuffer(NULL)
40 , fUnitSquareVertexBuffer(NULL)
41 , fDefaultPathRenderer(NULL)
42 , fClientPathRenderer(NULL)
43 , fContextIsDirty(true)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000044 , fResourceHead(NULL) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +000045
reed@google.comac10a2d2010-12-22 21:39:39 +000046#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000047 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000048#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000049
50 fGeomPoolStateStack.push_back();
51#if GR_DEBUG
52 GeometryPoolState& poolState = fGeomPoolStateStack.back();
53 poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
54 poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
55 poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
56 poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
57#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000058 resetStats();
59}
60
61GrGpu::~GrGpu() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 releaseResources();
reed@google.comac10a2d2010-12-22 21:39:39 +000063}
64
bsalomon@google.com8fe72472011-03-30 21:26:44 +000065void GrGpu::abandonResources() {
66
67 while (NULL != fResourceHead) {
68 fResourceHead->abandon();
69 }
70
71 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
72 GrAssert(NULL == fUnitSquareVertexBuffer ||
73 !fUnitSquareVertexBuffer->isValid());
74 GrSafeSetNull(fQuadIndexBuffer);
75 GrSafeSetNull(fUnitSquareVertexBuffer);
76 delete fVertexPool;
77 fVertexPool = NULL;
78 delete fIndexPool;
79 fIndexPool = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000080}
81
bsalomon@google.com8fe72472011-03-30 21:26:44 +000082void GrGpu::releaseResources() {
83
84 while (NULL != fResourceHead) {
85 fResourceHead->release();
86 }
87
88 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
89 GrAssert(NULL == fUnitSquareVertexBuffer ||
90 !fUnitSquareVertexBuffer->isValid());
91 GrSafeSetNull(fQuadIndexBuffer);
92 GrSafeSetNull(fUnitSquareVertexBuffer);
93 delete fVertexPool;
94 fVertexPool = NULL;
95 delete fIndexPool;
96 fIndexPool = NULL;
97}
98
99void GrGpu::insertResource(GrResource* resource) {
100 GrAssert(NULL != resource);
101 GrAssert(this == resource->getGpu());
102 GrAssert(NULL == resource->fNext);
103 GrAssert(NULL == resource->fPrevious);
104
105 resource->fNext = fResourceHead;
106 if (NULL != fResourceHead) {
107 GrAssert(NULL == fResourceHead->fPrevious);
108 fResourceHead->fPrevious = resource;
109 }
110 fResourceHead = resource;
111}
112
113void GrGpu::removeResource(GrResource* resource) {
114 GrAssert(NULL != resource);
115 GrAssert(NULL != fResourceHead);
116
117 if (fResourceHead == resource) {
118 GrAssert(NULL == resource->fPrevious);
119 fResourceHead = resource->fNext;
120 } else {
121 GrAssert(NULL != fResourceHead);
122 resource->fPrevious->fNext = resource->fNext;
123 }
124 if (NULL != resource->fNext) {
125 resource->fNext->fPrevious = resource->fPrevious;
126 }
127 resource->fNext = NULL;
128 resource->fPrevious = NULL;
129}
130
131
reed@google.comac10a2d2010-12-22 21:39:39 +0000132void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000133#if GR_DEBUG
134 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
135#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000136}
137
bsalomon@google.comd302f142011-03-03 13:54:13 +0000138////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000139
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000140GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000141 const void* srcData, size_t rowBytes) {
142 this->handleDirtyContext();
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000143 GrTexture* tex = this->onCreateTexture(desc, srcData, rowBytes);
144 if (NULL != tex &&
145 (kRenderTarget_GrTextureFlagBit & desc.fFlags) &&
146 !(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
147 GrAssert(NULL != tex->asRenderTarget());
148 // TODO: defer this and attach dynamically
149 if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) {
150 tex->unref();
151 return NULL;
152 }
153 }
154 return tex;
155}
156
157bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
158 // TODO: use a cache of stencil buffers rather than create per-rt.
bsalomon@google.comedc177d2011-08-05 15:46:40 +0000159 bool ret = this->createStencilBufferForRenderTarget(rt, rt->width(),
160 rt->height());
161 if (ret) {
162 // Right now we're clearing the stencil buffer here after it is
163 // attached to an RT for the first time. When we start matching
164 // stencil buffers with smaller color targets this will no longer
165 // be correct because it won't be guaranteed to clear the entire
166 // sb.
167 // We used to clear down in the GL subclass using a special purpose
168 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
169 // FBO status.
170 GrRenderTarget* oldRT = fCurrDrawState.fRenderTarget;
171 fCurrDrawState.fRenderTarget = rt;
172 this->clearStencil();
173 fCurrDrawState.fRenderTarget = oldRT;
174 }
175 return ret;
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000176}
177
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000178GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
179 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000180 return this->onCreateRenderTargetFrom3DApiState();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000181}
182
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000183GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
184 this->handleDirtyContext();
185 return this->onCreatePlatformSurface(desc);
186}
187
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000188GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
189 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000190 return this->onCreateVertexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000191}
192
193GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
194 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000195 return this->onCreateIndexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000196}
197
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000198void GrGpu::clear(const GrIRect* rect, GrColor color) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000199 this->handleDirtyContext();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000200 this->onClear(rect, color);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000201}
202
203void GrGpu::forceRenderTargetFlush() {
204 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000205 this->onForceRenderTargetFlush();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000206}
207
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000208bool GrGpu::readPixels(GrRenderTarget* target,
209 int left, int top, int width, int height,
210 GrPixelConfig config, void* buffer) {
211
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000212 this->handleDirtyContext();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000213 return this->onReadPixels(target, left, top, width, height, config, buffer);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000214}
215
216////////////////////////////////////////////////////////////////////////////////
217
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000218static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000219
reed@google.com8195f672011-01-12 18:14:28 +0000220GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000221
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000222static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000223 for (int i = 0; i < quadCount; ++i) {
224 indices[6 * i + 0] = 4 * i + 0;
225 indices[6 * i + 1] = 4 * i + 1;
226 indices[6 * i + 2] = 4 * i + 2;
227 indices[6 * i + 3] = 4 * i + 0;
228 indices[6 * i + 4] = 4 * i + 2;
229 indices[6 * i + 5] = 4 * i + 3;
230 }
231}
232
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000233const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000234 if (NULL == fQuadIndexBuffer) {
235 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
236 GrGpu* me = const_cast<GrGpu*>(this);
237 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
238 if (NULL != fQuadIndexBuffer) {
239 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
240 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000241 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000242 fQuadIndexBuffer->unlock();
243 } else {
244 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000245 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000246 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
247 fQuadIndexBuffer->unref();
248 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000249 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000250 }
251 GrFree(indices);
252 }
253 }
254 }
255
256 return fQuadIndexBuffer;
257}
258
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000259const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000260 if (NULL == fUnitSquareVertexBuffer) {
261
262 static const GrPoint DATA[] = {
reed@google.com7744c202011-05-06 19:26:26 +0000263 { 0, 0 },
264 { GR_Scalar1, 0 },
265 { GR_Scalar1, GR_Scalar1 },
266 { 0, GR_Scalar1 }
267#if 0
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000268 GrPoint(0, 0),
269 GrPoint(GR_Scalar1,0),
270 GrPoint(GR_Scalar1,GR_Scalar1),
271 GrPoint(0, GR_Scalar1)
reed@google.com7744c202011-05-06 19:26:26 +0000272#endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000273 };
274 static const size_t SIZE = sizeof(DATA);
275
276 GrGpu* me = const_cast<GrGpu*>(this);
277 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
278 if (NULL != fUnitSquareVertexBuffer) {
279 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
280 fUnitSquareVertexBuffer->unref();
281 fUnitSquareVertexBuffer = NULL;
282 GrCrash("Can't get vertices into buffer!");
283 }
284 }
285 }
286
287 return fUnitSquareVertexBuffer;
288}
289
bsalomon@google.comd302f142011-03-03 13:54:13 +0000290////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000291
bsalomon@google.comd302f142011-03-03 13:54:13 +0000292// stencil settings to use when clip is in stencil
293const GrStencilSettings GrGpu::gClipStencilSettings = {
294 kKeep_StencilOp, kKeep_StencilOp,
295 kKeep_StencilOp, kKeep_StencilOp,
296 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
297 0, 0,
298 0, 0,
299 0, 0
300};
301
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000302// mapping of clip-respecting stencil funcs to normal stencil funcs
303// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000304static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
305 {// Stencil-Clipping is DISABLED, effectively always inside the clip
306 // In the Clip Funcs
307 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
308 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
309 kLess_StencilFunc, // kLessIfInClip_StencilFunc
310 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
311 // Special in the clip func that forces user's ref to be 0.
312 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
313 // make ref 0 and do normal nequal.
314 },
315 {// Stencil-Clipping is ENABLED
316 // In the Clip Funcs
317 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
318 // eq stencil clip bit, mask
319 // out user bits.
320
321 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
322 // add stencil bit to mask and ref
323
324 kLess_StencilFunc, // kLessIfInClip_StencilFunc
325 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
326 // for both of these we can add
327 // the clip bit to the mask and
328 // ref and compare as normal
329 // Special in the clip func that forces user's ref to be 0.
330 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
331 // make ref have only the clip bit set
332 // and make comparison be less
333 // 10..0 < 1..user_bits..
334 }
335};
336
337GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
338 GrAssert(func >= 0);
339 if (func >= kBasicStencilFuncCount) {
340 GrAssert(func < kStencilFuncCount);
341 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
342 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
343 }
344 return func;
345}
346
347void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
348 bool clipInStencil,
349 unsigned int clipBit,
350 unsigned int userBits,
351 unsigned int* ref,
352 unsigned int* mask) {
353 if (func < kBasicStencilFuncCount) {
354 *mask &= userBits;
355 *ref &= userBits;
356 } else {
357 if (clipInStencil) {
358 switch (func) {
359 case kAlwaysIfInClip_StencilFunc:
360 *mask = clipBit;
361 *ref = clipBit;
362 break;
363 case kEqualIfInClip_StencilFunc:
364 case kLessIfInClip_StencilFunc:
365 case kLEqualIfInClip_StencilFunc:
366 *mask = (*mask & userBits) | clipBit;
367 *ref = (*ref & userBits) | clipBit;
368 break;
369 case kNonZeroIfInClip_StencilFunc:
370 *mask = (*mask & userBits) | clipBit;
371 *ref = clipBit;
372 break;
373 default:
374 GrCrash("Unknown stencil func");
375 }
376 } else {
377 *mask &= userBits;
378 *ref &= userBits;
379 }
380 }
381}
382
383////////////////////////////////////////////////////////////////////////////////
384
385#define VISUALIZE_COMPLEX_CLIP 0
386
387#if VISUALIZE_COMPLEX_CLIP
388 #include "GrRandom.h"
389 GrRandom gRandom;
390 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
391#else
392 #define SET_RANDOM_COLOR
393#endif
394
bsalomon@google.comffca4002011-02-22 20:34:01 +0000395bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000396 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000397 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000398
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000399 // we check this early because we need a valid
400 // render target to setup stencil clipping
401 // before even going into flushGraphicsState
402 if (NULL == fCurrDrawState.fRenderTarget) {
403 GrAssert(!"No render target bound.");
404 return false;
405 }
406
reed@google.comac10a2d2010-12-22 21:39:39 +0000407 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000408 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
409
410 GrRect bounds;
411 GrRect rtRect;
412 rtRect.setLTRB(0, 0,
413 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000414 if (fClip.hasConservativeBounds()) {
415 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000416 if (!bounds.intersect(rtRect)) {
417 bounds.setEmpty();
418 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000419 } else {
420 bounds = rtRect;
421 }
422
423 bounds.roundOut(&clipRect);
424 if (clipRect.isEmpty()) {
425 clipRect.setLTRB(0,0,0,0);
426 }
427 r = &clipRect;
428
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000429 // use the stencil clip if we can't represent the clip as a rectangle.
430 fClipInStencil = !fClip.isRect() && !fClip.isEmpty() &&
431 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000432
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000433 // TODO: dynamically attach a SB when needed.
434 GrStencilBuffer* stencilBuffer = rt.getStencilBuffer();
435 if (fClipInStencil && NULL == stencilBuffer) {
436 return false;
437 }
bsalomon@google.coma16d6502011-08-02 14:07:52 +0000438
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000439 if (fClipInStencil &&
440 stencilBuffer->mustRenderClip(fClip, rt.width(), rt.height())) {
441
442 stencilBuffer->setLastClip(fClip, rt.width(), rt.height());
443
bsalomon@google.comd302f142011-03-03 13:54:13 +0000444 // we set the current clip to the bounds so that our recursive
445 // draws are scissored to them. We use the copy of the complex clip
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000446 // we just stashed on the SB to render from. We set it back after
447 // we finish drawing it into the stencil.
448 const GrClip& clip = stencilBuffer->getLastClip();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000449 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000450
451 AutoStateRestore asr(this);
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000452 AutoGeometryPush agp(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000453
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000454 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000455 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000456 this->flushScissor(NULL);
457#if !VISUALIZE_COMPLEX_CLIP
458 this->enableState(kNoColorWrites_StateBit);
459#else
460 this->disableState(kNoColorWrites_StateBit);
461#endif
462 int count = clip.getElementCount();
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000463 int clipBit = stencilBuffer->bits();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000464 clipBit = (1 << (clipBit-1));
465
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000466 // often we'll see the first two elements of the clip are
467 // the full rt size and another element intersected with it.
468 // We can skip the first full-size rect and save a big rect draw.
469 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000470 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000471 kRect_ClipType == clip.getElementType(0) &&
472 kIntersect_SetOp == clip.getOp(1)&&
473 clip.getRect(0).contains(bounds)) {
474 firstElement = 1;
475 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000476
bsalomon@google.comd302f142011-03-03 13:54:13 +0000477 // walk through each clip element and perform its set op
478 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000479 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000480 GrPathFill fill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000481 bool fillInverted;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000482 // enabled at bottom of loop
483 this->disableState(kModifyStencilClip_StateBit);
484
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000485 bool canRenderDirectToStencil; // can the clip element be drawn
486 // directly to the stencil buffer
487 // with a non-inverted fill rule
488 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000489 // resolve in/out status.
490
491 GrPathRenderer* pr = NULL;
reed@google.com07f3ee12011-05-16 17:21:57 +0000492 const GrPath* clipPath = NULL;
bsalomon@google.comee435122011-07-01 14:57:55 +0000493 GrPathRenderer::AutoClearPath arp;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000494 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000495 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000496 fill = kEvenOdd_PathFill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000497 fillInverted = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000498 } else {
499 fill = clip.getPathFill(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000500 fillInverted = IsFillInverted(fill);
501 fill = NonInvertedFill(fill);
reed@google.com07f3ee12011-05-16 17:21:57 +0000502 clipPath = &clip.getPath(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000503 pr = this->getClipPathRenderer(*clipPath, fill);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000504 canRenderDirectToStencil =
bsalomon@google.comee435122011-07-01 14:57:55 +0000505 !pr->requiresStencilPass(this, *clipPath, fill);
506 arp.set(pr, this, clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000507 }
508
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000509 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000510 int passes;
511 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
512
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000513 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000514 // fill rule, and set operation can
515 // we render the element directly to
516 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000517 canDrawDirectToClip =
518 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000519 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000520 clipBit,
bsalomon@google.comee435122011-07-01 14:57:55 +0000521 fillInverted,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000522 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000523
524 // draw the element to the client stencil bits if necessary
525 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000526 static const GrStencilSettings gDrawToStencil = {
527 kIncClamp_StencilOp, kIncClamp_StencilOp,
528 kIncClamp_StencilOp, kIncClamp_StencilOp,
529 kAlways_StencilFunc, kAlways_StencilFunc,
530 0xffffffff, 0xffffffff,
531 0x00000000, 0x00000000,
532 0xffffffff, 0xffffffff,
533 };
534 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000535 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000536 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000537 this->drawSimpleRect(clip.getRect(c), NULL, 0);
538 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000539 if (canRenderDirectToStencil) {
540 this->setStencil(gDrawToStencil);
bsalomon@google.comee435122011-07-01 14:57:55 +0000541 pr->drawPath(0);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000542 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000543 pr->drawPathToStencil();
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000544 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000545 }
546 }
547
548 // now we modify the clip bit by rendering either the clip
549 // element directly or a bounding rect of the entire clip.
550 this->enableState(kModifyStencilClip_StateBit);
551 for (int p = 0; p < passes; ++p) {
552 this->setStencil(stencilSettings[p]);
553 if (canDrawDirectToClip) {
554 if (kRect_ClipType == clip.getElementType(c)) {
555 SET_RANDOM_COLOR
556 this->drawSimpleRect(clip.getRect(c), NULL, 0);
557 } else {
558 SET_RANDOM_COLOR
bsalomon@google.comee435122011-07-01 14:57:55 +0000559 pr->drawPath(0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000560 }
561 } else {
562 SET_RANDOM_COLOR
thakis@chromium.org441d7da2011-06-07 04:03:17 +0000563 this->drawSimpleRect(bounds, NULL, 0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000564 }
565 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000566 }
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000567 // restore clip
bsalomon@google.comd302f142011-03-03 13:54:13 +0000568 fClip = clip;
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000569 // recusive draws would have disabled this since they drew with
570 // the clip bounds as clip.
571 fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000572 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000573 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000574
reed@google.comac10a2d2010-12-22 21:39:39 +0000575 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000576 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000577 return false;
578 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000579 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000580 return true;
581}
582
reed@google.com07f3ee12011-05-16 17:21:57 +0000583GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000584 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000585 if (NULL != fClientPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +0000586 fClientPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000587 return fClientPathRenderer;
588 } else {
589 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000590 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000591 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
592 this->supportsStencilWrapOps());
593 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000594 GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000595 return fDefaultPathRenderer;
596 }
597}
598
599
bsalomon@google.comd302f142011-03-03 13:54:13 +0000600////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000601
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000602void GrGpu::geometrySourceWillPush() {
603 const GeometrySrcState& geoSrc = this->getGeomSrc();
604 if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
605 kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
606 this->finalizeReservedVertices();
607 }
608 if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
609 kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
610 this->finalizeReservedIndices();
611 }
612 GeometryPoolState& newState = fGeomPoolStateStack.push_back();
613#if GR_DEBUG
614 newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
615 newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
616 newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
617 newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
618#endif
619}
620
621void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
622 // if popping last entry then pops are unbalanced with pushes
623 GrAssert(fGeomPoolStateStack.count() > 1);
624 fGeomPoolStateStack.pop_back();
625}
626
627void GrGpu::onDrawIndexed(GrPrimitiveType type,
628 int startVertex,
629 int startIndex,
630 int vertexCount,
631 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000632
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000633 this->handleDirtyContext();
634
635 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000636 return;
637 }
638
639#if GR_COLLECT_STATS
640 fStats.fVertexCnt += vertexCount;
641 fStats.fIndexCnt += indexCount;
642 fStats.fDrawCnt += 1;
643#endif
644
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000645 int sVertex = startVertex;
646 int sIndex = startIndex;
647 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000648
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000649 this->onGpuDrawIndexed(type, sVertex, sIndex,
650 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000651}
652
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000653void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000654 int startVertex,
655 int vertexCount) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000656 this->handleDirtyContext();
657
658 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000659 return;
660 }
661#if GR_COLLECT_STATS
662 fStats.fVertexCnt += vertexCount;
663 fStats.fDrawCnt += 1;
664#endif
665
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000666 int sVertex = startVertex;
667 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000668
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000669 this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000670}
671
672void GrGpu::finalizeReservedVertices() {
673 GrAssert(NULL != fVertexPool);
674 fVertexPool->unlock();
675}
676
677void GrGpu::finalizeReservedIndices() {
678 GrAssert(NULL != fIndexPool);
679 fIndexPool->unlock();
680}
681
682void GrGpu::prepareVertexPool() {
683 if (NULL == fVertexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000684 GrAssert(0 == fVertexPoolUseCnt);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000685 fVertexPool = new GrVertexBufferAllocPool(this, true,
686 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000687 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000688 fVertexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000689 } else if (!fVertexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000690 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000691 fVertexPool->reset();
692 }
693}
694
695void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000696 if (NULL == fIndexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000697 GrAssert(0 == fIndexPoolUseCnt);
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000698 fIndexPool = new GrIndexBufferAllocPool(this, true,
699 INDEX_POOL_IB_SIZE,
700 INDEX_POOL_IB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000701 fIndexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000702 } else if (!fIndexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000703 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000704 fIndexPool->reset();
705 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000706}
707
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000708bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
709 int vertexCount,
710 void** vertices) {
711 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
712
713 GrAssert(vertexCount > 0);
714 GrAssert(NULL != vertices);
715
716 this->prepareVertexPool();
717
718 *vertices = fVertexPool->makeSpace(vertexLayout,
719 vertexCount,
720 &geomPoolState.fPoolVertexBuffer,
721 &geomPoolState.fPoolStartVertex);
722 if (NULL == *vertices) {
723 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000724 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000725 ++fVertexPoolUseCnt;
reed@google.comac10a2d2010-12-22 21:39:39 +0000726 return true;
727}
728
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000729bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
730 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
731
732 GrAssert(indexCount > 0);
733 GrAssert(NULL != indices);
734
735 this->prepareIndexPool();
736
737 *indices = fIndexPool->makeSpace(indexCount,
738 &geomPoolState.fPoolIndexBuffer,
739 &geomPoolState.fPoolStartIndex);
740 if (NULL == *indices) {
741 return false;
742 }
743 ++fIndexPoolUseCnt;
744 return true;
745}
746
747void GrGpu::releaseReservedVertexSpace() {
748 const GeometrySrcState& geoSrc = this->getGeomSrc();
749 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
750 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
751 fVertexPool->putBack(bytes);
752 --fVertexPoolUseCnt;
753}
754
755void GrGpu::releaseReservedIndexSpace() {
756 const GeometrySrcState& geoSrc = this->getGeomSrc();
757 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
758 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
759 fIndexPool->putBack(bytes);
760 --fIndexPoolUseCnt;
761}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000762
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000763void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000764 this->prepareVertexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000765 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000766#if GR_DEBUG
767 bool success =
768#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000769 fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000770 vertexCount,
771 vertexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000772 &geomPoolState.fPoolVertexBuffer,
773 &geomPoolState.fPoolStartVertex);
774 ++fVertexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000775 GR_DEBUGASSERT(success);
776}
777
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000778void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000779 this->prepareIndexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000780 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000781#if GR_DEBUG
782 bool success =
783#endif
784 fIndexPool->appendIndices(indexCount,
785 indexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000786 &geomPoolState.fPoolIndexBuffer,
787 &geomPoolState.fPoolStartIndex);
788 ++fIndexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000789 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000790}
791
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000792void GrGpu::releaseVertexArray() {
793 // if vertex source was array, we stowed data in the pool
794 const GeometrySrcState& geoSrc = this->getGeomSrc();
795 GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
796 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
797 fVertexPool->putBack(bytes);
798 --fVertexPoolUseCnt;
799}
800
801void GrGpu::releaseIndexArray() {
802 // if index source was array, we stowed data in the pool
803 const GeometrySrcState& geoSrc = this->getGeomSrc();
804 GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
805 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
806 fIndexPool->putBack(bytes);
807 --fIndexPoolUseCnt;
808}
809
bsalomon@google.comd302f142011-03-03 13:54:13 +0000810////////////////////////////////////////////////////////////////////////////////
811
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000812const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000813 return fStats;
814}
815
816void GrGpu::resetStats() {
817 memset(&fStats, 0, sizeof(fStats));
818}
819
820void GrGpu::printStats() const {
821 if (GR_COLLECT_STATS) {
822 GrPrintf(
823 "-v-------------------------GPU STATS----------------------------v-\n"
824 "Stats collection is: %s\n"
825 "Draws: %04d, Verts: %04d, Indices: %04d\n"
826 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
827 "TexCreates: %04d, RTCreates:%04d\n"
828 "-^--------------------------------------------------------------^-\n",
829 (GR_COLLECT_STATS ? "ON" : "OFF"),
830 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
831 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
832 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
833 }
834}
835
836////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000837const GrSamplerState GrSamplerState::gClampNoFilter(
838 GrSamplerState::kClamp_WrapMode,
839 GrSamplerState::kClamp_WrapMode,
840 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000841 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000842 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000843
844
845
846