blob: 007ea3170f1df972656690719fc7367e41e98372 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
reed@google.comac10a2d2010-12-22 21:39:39 +000017#include "GrGpu.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000018#include "GrTextStrike.h"
19#include "GrTextureCache.h"
20#include "GrClipIterator.h"
21#include "GrIndexBuffer.h"
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000022#include "GrVertexBuffer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000023#include "GrBufferAllocPool.h"
bsalomon@google.comd302f142011-03-03 13:54:13 +000024#include "GrPathRenderer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000025
26// probably makes no sense for this to be less than a page
bsalomon@google.comee435122011-07-01 14:57:55 +000027static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
28static const int VERTEX_POOL_VB_COUNT = 4;
bsalomon@google.com25fd36c2011-07-06 17:41:08 +000029static const size_t INDEX_POOL_IB_SIZE = 1 << 16;
30static const int INDEX_POOL_IB_COUNT = 4;
reed@google.comac10a2d2010-12-22 21:39:39 +000031
bsalomon@google.comd302f142011-03-03 13:54:13 +000032////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000033
34extern void gr_run_unittests();
35
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000036#define DEBUG_INVAL_BUFFER 0xdeadcafe
37#define DEBUG_INVAL_START_IDX -1
38
bsalomon@google.com8fe72472011-03-30 21:26:44 +000039GrGpu::GrGpu()
40 : f8bitPaletteSupport(false)
bsalomon@google.com669fdc42011-04-05 17:08:27 +000041 , fContext(NULL)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000042 , fVertexPool(NULL)
43 , fIndexPool(NULL)
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000044 , fVertexPoolUseCnt(0)
45 , fIndexPoolUseCnt(0)
46 , fGeomPoolStateStack(&fGeoSrcStateStackStorage)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000047 , fQuadIndexBuffer(NULL)
48 , fUnitSquareVertexBuffer(NULL)
49 , fDefaultPathRenderer(NULL)
50 , fClientPathRenderer(NULL)
51 , fContextIsDirty(true)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000052 , fResourceHead(NULL) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +000053
reed@google.comac10a2d2010-12-22 21:39:39 +000054#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000055 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000056#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000057
58 fGeomPoolStateStack.push_back();
59#if GR_DEBUG
60 GeometryPoolState& poolState = fGeomPoolStateStack.back();
61 poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
62 poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
63 poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
64 poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
65#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000066 resetStats();
67}
68
69GrGpu::~GrGpu() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000070 releaseResources();
reed@google.comac10a2d2010-12-22 21:39:39 +000071}
72
bsalomon@google.com8fe72472011-03-30 21:26:44 +000073void GrGpu::abandonResources() {
74
75 while (NULL != fResourceHead) {
76 fResourceHead->abandon();
77 }
78
79 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
80 GrAssert(NULL == fUnitSquareVertexBuffer ||
81 !fUnitSquareVertexBuffer->isValid());
82 GrSafeSetNull(fQuadIndexBuffer);
83 GrSafeSetNull(fUnitSquareVertexBuffer);
84 delete fVertexPool;
85 fVertexPool = NULL;
86 delete fIndexPool;
87 fIndexPool = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000088}
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090void GrGpu::releaseResources() {
91
92 while (NULL != fResourceHead) {
93 fResourceHead->release();
94 }
95
96 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
97 GrAssert(NULL == fUnitSquareVertexBuffer ||
98 !fUnitSquareVertexBuffer->isValid());
99 GrSafeSetNull(fQuadIndexBuffer);
100 GrSafeSetNull(fUnitSquareVertexBuffer);
101 delete fVertexPool;
102 fVertexPool = NULL;
103 delete fIndexPool;
104 fIndexPool = NULL;
105}
106
107void GrGpu::insertResource(GrResource* resource) {
108 GrAssert(NULL != resource);
109 GrAssert(this == resource->getGpu());
110 GrAssert(NULL == resource->fNext);
111 GrAssert(NULL == resource->fPrevious);
112
113 resource->fNext = fResourceHead;
114 if (NULL != fResourceHead) {
115 GrAssert(NULL == fResourceHead->fPrevious);
116 fResourceHead->fPrevious = resource;
117 }
118 fResourceHead = resource;
119}
120
121void GrGpu::removeResource(GrResource* resource) {
122 GrAssert(NULL != resource);
123 GrAssert(NULL != fResourceHead);
124
125 if (fResourceHead == resource) {
126 GrAssert(NULL == resource->fPrevious);
127 fResourceHead = resource->fNext;
128 } else {
129 GrAssert(NULL != fResourceHead);
130 resource->fPrevious->fNext = resource->fNext;
131 }
132 if (NULL != resource->fNext) {
133 resource->fNext->fPrevious = resource->fPrevious;
134 }
135 resource->fNext = NULL;
136 resource->fPrevious = NULL;
137}
138
139
reed@google.comac10a2d2010-12-22 21:39:39 +0000140void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000141#if GR_DEBUG
142 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
143#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000144}
145
bsalomon@google.comd302f142011-03-03 13:54:13 +0000146////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000147
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000148GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000149 const void* srcData, size_t rowBytes) {
150 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000151 return this->onCreateTexture(desc, srcData, rowBytes);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000152}
153
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000154GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
155 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000156 return this->onCreateRenderTargetFrom3DApiState();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000157}
158
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000159GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
160 this->handleDirtyContext();
161 return this->onCreatePlatformSurface(desc);
162}
163
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000164GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
165 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000166 return this->onCreateVertexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000167}
168
169GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
170 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000171 return this->onCreateIndexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000172}
173
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000174void GrGpu::clear(const GrIRect* rect, GrColor color) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000175 this->handleDirtyContext();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000176 this->onClear(rect, color);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000177}
178
179void GrGpu::forceRenderTargetFlush() {
180 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000181 this->onForceRenderTargetFlush();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000182}
183
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000184bool GrGpu::readPixels(GrRenderTarget* target,
185 int left, int top, int width, int height,
186 GrPixelConfig config, void* buffer) {
187
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000188 this->handleDirtyContext();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000189 return this->onReadPixels(target, left, top, width, height, config, buffer);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000190}
191
192////////////////////////////////////////////////////////////////////////////////
193
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000194static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000195
reed@google.com8195f672011-01-12 18:14:28 +0000196GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000197
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000198static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000199 for (int i = 0; i < quadCount; ++i) {
200 indices[6 * i + 0] = 4 * i + 0;
201 indices[6 * i + 1] = 4 * i + 1;
202 indices[6 * i + 2] = 4 * i + 2;
203 indices[6 * i + 3] = 4 * i + 0;
204 indices[6 * i + 4] = 4 * i + 2;
205 indices[6 * i + 5] = 4 * i + 3;
206 }
207}
208
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000209const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000210 if (NULL == fQuadIndexBuffer) {
211 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
212 GrGpu* me = const_cast<GrGpu*>(this);
213 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
214 if (NULL != fQuadIndexBuffer) {
215 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
216 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000217 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000218 fQuadIndexBuffer->unlock();
219 } else {
220 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000221 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000222 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
223 fQuadIndexBuffer->unref();
224 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000225 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000226 }
227 GrFree(indices);
228 }
229 }
230 }
231
232 return fQuadIndexBuffer;
233}
234
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000235const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000236 if (NULL == fUnitSquareVertexBuffer) {
237
238 static const GrPoint DATA[] = {
reed@google.com7744c202011-05-06 19:26:26 +0000239 { 0, 0 },
240 { GR_Scalar1, 0 },
241 { GR_Scalar1, GR_Scalar1 },
242 { 0, GR_Scalar1 }
243#if 0
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000244 GrPoint(0, 0),
245 GrPoint(GR_Scalar1,0),
246 GrPoint(GR_Scalar1,GR_Scalar1),
247 GrPoint(0, GR_Scalar1)
reed@google.com7744c202011-05-06 19:26:26 +0000248#endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000249 };
250 static const size_t SIZE = sizeof(DATA);
251
252 GrGpu* me = const_cast<GrGpu*>(this);
253 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
254 if (NULL != fUnitSquareVertexBuffer) {
255 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
256 fUnitSquareVertexBuffer->unref();
257 fUnitSquareVertexBuffer = NULL;
258 GrCrash("Can't get vertices into buffer!");
259 }
260 }
261 }
262
263 return fUnitSquareVertexBuffer;
264}
265
bsalomon@google.comd302f142011-03-03 13:54:13 +0000266////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000267
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000268void GrGpu::clipWillBeSet(const GrClip& newClip) {
269 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000270 fClipState.fClipIsDirty = true;
271 }
272}
273
bsalomon@google.comd302f142011-03-03 13:54:13 +0000274////////////////////////////////////////////////////////////////////////////////
275
276// stencil settings to use when clip is in stencil
277const GrStencilSettings GrGpu::gClipStencilSettings = {
278 kKeep_StencilOp, kKeep_StencilOp,
279 kKeep_StencilOp, kKeep_StencilOp,
280 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
281 0, 0,
282 0, 0,
283 0, 0
284};
285
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000286// mapping of clip-respecting stencil funcs to normal stencil funcs
287// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000288static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
289 {// Stencil-Clipping is DISABLED, effectively always inside the clip
290 // In the Clip Funcs
291 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
292 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
293 kLess_StencilFunc, // kLessIfInClip_StencilFunc
294 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
295 // Special in the clip func that forces user's ref to be 0.
296 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
297 // make ref 0 and do normal nequal.
298 },
299 {// Stencil-Clipping is ENABLED
300 // In the Clip Funcs
301 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
302 // eq stencil clip bit, mask
303 // out user bits.
304
305 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
306 // add stencil bit to mask and ref
307
308 kLess_StencilFunc, // kLessIfInClip_StencilFunc
309 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
310 // for both of these we can add
311 // the clip bit to the mask and
312 // ref and compare as normal
313 // Special in the clip func that forces user's ref to be 0.
314 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
315 // make ref have only the clip bit set
316 // and make comparison be less
317 // 10..0 < 1..user_bits..
318 }
319};
320
321GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
322 GrAssert(func >= 0);
323 if (func >= kBasicStencilFuncCount) {
324 GrAssert(func < kStencilFuncCount);
325 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
326 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
327 }
328 return func;
329}
330
331void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
332 bool clipInStencil,
333 unsigned int clipBit,
334 unsigned int userBits,
335 unsigned int* ref,
336 unsigned int* mask) {
337 if (func < kBasicStencilFuncCount) {
338 *mask &= userBits;
339 *ref &= userBits;
340 } else {
341 if (clipInStencil) {
342 switch (func) {
343 case kAlwaysIfInClip_StencilFunc:
344 *mask = clipBit;
345 *ref = clipBit;
346 break;
347 case kEqualIfInClip_StencilFunc:
348 case kLessIfInClip_StencilFunc:
349 case kLEqualIfInClip_StencilFunc:
350 *mask = (*mask & userBits) | clipBit;
351 *ref = (*ref & userBits) | clipBit;
352 break;
353 case kNonZeroIfInClip_StencilFunc:
354 *mask = (*mask & userBits) | clipBit;
355 *ref = clipBit;
356 break;
357 default:
358 GrCrash("Unknown stencil func");
359 }
360 } else {
361 *mask &= userBits;
362 *ref &= userBits;
363 }
364 }
365}
366
367////////////////////////////////////////////////////////////////////////////////
368
369#define VISUALIZE_COMPLEX_CLIP 0
370
371#if VISUALIZE_COMPLEX_CLIP
372 #include "GrRandom.h"
373 GrRandom gRandom;
374 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
375#else
376 #define SET_RANDOM_COLOR
377#endif
378
bsalomon@google.comffca4002011-02-22 20:34:01 +0000379bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000380 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000381 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000382
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000383 // we check this early because we need a valid
384 // render target to setup stencil clipping
385 // before even going into flushGraphicsState
386 if (NULL == fCurrDrawState.fRenderTarget) {
387 GrAssert(!"No render target bound.");
388 return false;
389 }
390
reed@google.comac10a2d2010-12-22 21:39:39 +0000391 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000392 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
393
394 GrRect bounds;
395 GrRect rtRect;
396 rtRect.setLTRB(0, 0,
397 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000398 if (fClip.hasConservativeBounds()) {
399 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000400 if (!bounds.intersect(rtRect)) {
401 bounds.setEmpty();
402 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000403 } else {
404 bounds = rtRect;
405 }
406
407 bounds.roundOut(&clipRect);
408 if (clipRect.isEmpty()) {
409 clipRect.setLTRB(0,0,0,0);
410 }
411 r = &clipRect;
412
413 fClipState.fClipInStencil = !fClip.isRect() &&
414 !fClip.isEmpty() &&
415 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000416
417 if (fClipState.fClipInStencil &&
418 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000419 fClip != rt.fLastStencilClip)) {
420
421 rt.fLastStencilClip = fClip;
422 // we set the current clip to the bounds so that our recursive
423 // draws are scissored to them. We use the copy of the complex clip
424 // in the rt to render
425 const GrClip& clip = rt.fLastStencilClip;
426 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000427
428 AutoStateRestore asr(this);
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000429 AutoGeometryPush agp(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000430
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000431 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000432 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000433 this->flushScissor(NULL);
434#if !VISUALIZE_COMPLEX_CLIP
435 this->enableState(kNoColorWrites_StateBit);
436#else
437 this->disableState(kNoColorWrites_StateBit);
438#endif
439 int count = clip.getElementCount();
440 int clipBit = rt.stencilBits();
441 clipBit = (1 << (clipBit-1));
442
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000443 // often we'll see the first two elements of the clip are
444 // the full rt size and another element intersected with it.
445 // We can skip the first full-size rect and save a big rect draw.
446 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000447 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000448 kRect_ClipType == clip.getElementType(0) &&
449 kIntersect_SetOp == clip.getOp(1)&&
450 clip.getRect(0).contains(bounds)) {
451 firstElement = 1;
452 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000453
bsalomon@google.comd302f142011-03-03 13:54:13 +0000454 // walk through each clip element and perform its set op
455 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000456 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000457 GrPathFill fill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000458 bool fillInverted;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000459 // enabled at bottom of loop
460 this->disableState(kModifyStencilClip_StateBit);
461
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000462 bool canRenderDirectToStencil; // can the clip element be drawn
463 // directly to the stencil buffer
464 // with a non-inverted fill rule
465 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000466 // resolve in/out status.
467
468 GrPathRenderer* pr = NULL;
reed@google.com07f3ee12011-05-16 17:21:57 +0000469 const GrPath* clipPath = NULL;
bsalomon@google.comee435122011-07-01 14:57:55 +0000470 GrPathRenderer::AutoClearPath arp;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000471 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000472 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000473 fill = kEvenOdd_PathFill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000474 fillInverted = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000475 } else {
476 fill = clip.getPathFill(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000477 fillInverted = IsFillInverted(fill);
478 fill = NonInvertedFill(fill);
reed@google.com07f3ee12011-05-16 17:21:57 +0000479 clipPath = &clip.getPath(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000480 pr = this->getClipPathRenderer(*clipPath, fill);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000481 canRenderDirectToStencil =
bsalomon@google.comee435122011-07-01 14:57:55 +0000482 !pr->requiresStencilPass(this, *clipPath, fill);
483 arp.set(pr, this, clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000484 }
485
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000486 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000487 int passes;
488 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
489
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000490 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000491 // fill rule, and set operation can
492 // we render the element directly to
493 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000494 canDrawDirectToClip =
495 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000496 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000497 clipBit,
bsalomon@google.comee435122011-07-01 14:57:55 +0000498 fillInverted,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000499 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000500
501 // draw the element to the client stencil bits if necessary
502 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000503 static const GrStencilSettings gDrawToStencil = {
504 kIncClamp_StencilOp, kIncClamp_StencilOp,
505 kIncClamp_StencilOp, kIncClamp_StencilOp,
506 kAlways_StencilFunc, kAlways_StencilFunc,
507 0xffffffff, 0xffffffff,
508 0x00000000, 0x00000000,
509 0xffffffff, 0xffffffff,
510 };
511 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000512 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000513 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000514 this->drawSimpleRect(clip.getRect(c), NULL, 0);
515 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000516 if (canRenderDirectToStencil) {
517 this->setStencil(gDrawToStencil);
bsalomon@google.comee435122011-07-01 14:57:55 +0000518 pr->drawPath(0);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000519 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000520 pr->drawPathToStencil();
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000521 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000522 }
523 }
524
525 // now we modify the clip bit by rendering either the clip
526 // element directly or a bounding rect of the entire clip.
527 this->enableState(kModifyStencilClip_StateBit);
528 for (int p = 0; p < passes; ++p) {
529 this->setStencil(stencilSettings[p]);
530 if (canDrawDirectToClip) {
531 if (kRect_ClipType == clip.getElementType(c)) {
532 SET_RANDOM_COLOR
533 this->drawSimpleRect(clip.getRect(c), NULL, 0);
534 } else {
535 SET_RANDOM_COLOR
bsalomon@google.comee435122011-07-01 14:57:55 +0000536 pr->drawPath(0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000537 }
538 } else {
539 SET_RANDOM_COLOR
thakis@chromium.org441d7da2011-06-07 04:03:17 +0000540 this->drawSimpleRect(bounds, NULL, 0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000541 }
542 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000543 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000544 fClip = clip;
545 // recusive draws would have disabled this.
546 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000547 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000548
reed@google.comac10a2d2010-12-22 21:39:39 +0000549 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000550 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000551
reed@google.comac10a2d2010-12-22 21:39:39 +0000552 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000553 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000554 return false;
555 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000556 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000557 return true;
558}
559
reed@google.com07f3ee12011-05-16 17:21:57 +0000560GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000561 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000562 if (NULL != fClientPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +0000563 fClientPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000564 return fClientPathRenderer;
565 } else {
566 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000567 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000568 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
569 this->supportsStencilWrapOps());
570 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000571 GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000572 return fDefaultPathRenderer;
573 }
574}
575
576
bsalomon@google.comd302f142011-03-03 13:54:13 +0000577////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000578
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000579void GrGpu::geometrySourceWillPush() {
580 const GeometrySrcState& geoSrc = this->getGeomSrc();
581 if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
582 kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
583 this->finalizeReservedVertices();
584 }
585 if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
586 kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
587 this->finalizeReservedIndices();
588 }
589 GeometryPoolState& newState = fGeomPoolStateStack.push_back();
590#if GR_DEBUG
591 newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
592 newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
593 newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
594 newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
595#endif
596}
597
598void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
599 // if popping last entry then pops are unbalanced with pushes
600 GrAssert(fGeomPoolStateStack.count() > 1);
601 fGeomPoolStateStack.pop_back();
602}
603
604void GrGpu::onDrawIndexed(GrPrimitiveType type,
605 int startVertex,
606 int startIndex,
607 int vertexCount,
608 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000609
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000610 this->handleDirtyContext();
611
612 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000613 return;
614 }
615
616#if GR_COLLECT_STATS
617 fStats.fVertexCnt += vertexCount;
618 fStats.fIndexCnt += indexCount;
619 fStats.fDrawCnt += 1;
620#endif
621
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000622 int sVertex = startVertex;
623 int sIndex = startIndex;
624 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000625
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000626 this->onGpuDrawIndexed(type, sVertex, sIndex,
627 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000628}
629
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000630void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000631 int startVertex,
632 int vertexCount) {
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#if GR_COLLECT_STATS
639 fStats.fVertexCnt += vertexCount;
640 fStats.fDrawCnt += 1;
641#endif
642
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000643 int sVertex = startVertex;
644 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000645
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000646 this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000647}
648
649void GrGpu::finalizeReservedVertices() {
650 GrAssert(NULL != fVertexPool);
651 fVertexPool->unlock();
652}
653
654void GrGpu::finalizeReservedIndices() {
655 GrAssert(NULL != fIndexPool);
656 fIndexPool->unlock();
657}
658
659void GrGpu::prepareVertexPool() {
660 if (NULL == fVertexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000661 GrAssert(0 == fVertexPoolUseCnt);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000662 fVertexPool = new GrVertexBufferAllocPool(this, true,
663 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000664 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000665 fVertexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000666 } else if (!fVertexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000667 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000668 fVertexPool->reset();
669 }
670}
671
672void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000673 if (NULL == fIndexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000674 GrAssert(0 == fIndexPoolUseCnt);
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000675 fIndexPool = new GrIndexBufferAllocPool(this, true,
676 INDEX_POOL_IB_SIZE,
677 INDEX_POOL_IB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000678 fIndexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000679 } else if (!fIndexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000680 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000681 fIndexPool->reset();
682 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000683}
684
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000685bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
686 int vertexCount,
687 void** vertices) {
688 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
689
690 GrAssert(vertexCount > 0);
691 GrAssert(NULL != vertices);
692
693 this->prepareVertexPool();
694
695 *vertices = fVertexPool->makeSpace(vertexLayout,
696 vertexCount,
697 &geomPoolState.fPoolVertexBuffer,
698 &geomPoolState.fPoolStartVertex);
699 if (NULL == *vertices) {
700 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000701 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000702 ++fVertexPoolUseCnt;
reed@google.comac10a2d2010-12-22 21:39:39 +0000703 return true;
704}
705
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000706bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
707 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
708
709 GrAssert(indexCount > 0);
710 GrAssert(NULL != indices);
711
712 this->prepareIndexPool();
713
714 *indices = fIndexPool->makeSpace(indexCount,
715 &geomPoolState.fPoolIndexBuffer,
716 &geomPoolState.fPoolStartIndex);
717 if (NULL == *indices) {
718 return false;
719 }
720 ++fIndexPoolUseCnt;
721 return true;
722}
723
724void GrGpu::releaseReservedVertexSpace() {
725 const GeometrySrcState& geoSrc = this->getGeomSrc();
726 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
727 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
728 fVertexPool->putBack(bytes);
729 --fVertexPoolUseCnt;
730}
731
732void GrGpu::releaseReservedIndexSpace() {
733 const GeometrySrcState& geoSrc = this->getGeomSrc();
734 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
735 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
736 fIndexPool->putBack(bytes);
737 --fIndexPoolUseCnt;
738}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000739
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000740void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000741 this->prepareVertexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000742 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000743#if GR_DEBUG
744 bool success =
745#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000746 fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000747 vertexCount,
748 vertexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000749 &geomPoolState.fPoolVertexBuffer,
750 &geomPoolState.fPoolStartVertex);
751 ++fVertexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000752 GR_DEBUGASSERT(success);
753}
754
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000755void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000756 this->prepareIndexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000757 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000758#if GR_DEBUG
759 bool success =
760#endif
761 fIndexPool->appendIndices(indexCount,
762 indexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000763 &geomPoolState.fPoolIndexBuffer,
764 &geomPoolState.fPoolStartIndex);
765 ++fIndexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000766 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000767}
768
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000769void GrGpu::releaseVertexArray() {
770 // if vertex source was array, we stowed data in the pool
771 const GeometrySrcState& geoSrc = this->getGeomSrc();
772 GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
773 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
774 fVertexPool->putBack(bytes);
775 --fVertexPoolUseCnt;
776}
777
778void GrGpu::releaseIndexArray() {
779 // if index source was array, we stowed data in the pool
780 const GeometrySrcState& geoSrc = this->getGeomSrc();
781 GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
782 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
783 fIndexPool->putBack(bytes);
784 --fIndexPoolUseCnt;
785}
786
bsalomon@google.comd302f142011-03-03 13:54:13 +0000787////////////////////////////////////////////////////////////////////////////////
788
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000789const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000790 return fStats;
791}
792
793void GrGpu::resetStats() {
794 memset(&fStats, 0, sizeof(fStats));
795}
796
797void GrGpu::printStats() const {
798 if (GR_COLLECT_STATS) {
799 GrPrintf(
800 "-v-------------------------GPU STATS----------------------------v-\n"
801 "Stats collection is: %s\n"
802 "Draws: %04d, Verts: %04d, Indices: %04d\n"
803 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
804 "TexCreates: %04d, RTCreates:%04d\n"
805 "-^--------------------------------------------------------------^-\n",
806 (GR_COLLECT_STATS ? "ON" : "OFF"),
807 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
808 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
809 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
810 }
811}
812
813////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000814const GrSamplerState GrSamplerState::gClampNoFilter(
815 GrSamplerState::kClamp_WrapMode,
816 GrSamplerState::kClamp_WrapMode,
817 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000818 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000819 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000820
821
822
823