blob: db7de2c39f837090916dad0bd3ccd8c2a7fa37bc [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"
18#include "GrMemory.h"
19#include "GrTextStrike.h"
20#include "GrTextureCache.h"
21#include "GrClipIterator.h"
22#include "GrIndexBuffer.h"
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000023#include "GrVertexBuffer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000024#include "GrBufferAllocPool.h"
bsalomon@google.comd302f142011-03-03 13:54:13 +000025#include "GrPathRenderer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000026
27// probably makes no sense for this to be less than a page
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +000028static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
29static const int VERTEX_POOL_VB_COUNT = 1;
reed@google.comac10a2d2010-12-22 21:39:39 +000030
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;
458 // enabled at bottom of loop
459 this->disableState(kModifyStencilClip_StateBit);
460
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000461 bool canRenderDirectToStencil; // can the clip element be drawn
462 // directly to the stencil buffer
463 // with a non-inverted fill rule
464 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000465 // resolve in/out status.
466
467 GrPathRenderer* pr = NULL;
reed@google.com07f3ee12011-05-16 17:21:57 +0000468 const GrPath* clipPath = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000469 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000470 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000471 fill = kEvenOdd_PathFill;
472 } else {
473 fill = clip.getPathFill(c);
reed@google.com07f3ee12011-05-16 17:21:57 +0000474 clipPath = &clip.getPath(c);
475 pr = this->getClipPathRenderer(*clipPath, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000476 canRenderDirectToStencil =
reed@google.com07f3ee12011-05-16 17:21:57 +0000477 !pr->requiresStencilPass(this, *clipPath,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000478 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000479 }
480
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000481 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000482 int passes;
483 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
484
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000485 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000486 // fill rule, and set operation can
487 // we render the element directly to
488 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000489 canDrawDirectToClip =
490 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000491 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000492 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000493 IsFillInverted(fill),
494 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000495
496 // draw the element to the client stencil bits if necessary
497 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000498 static const GrStencilSettings gDrawToStencil = {
499 kIncClamp_StencilOp, kIncClamp_StencilOp,
500 kIncClamp_StencilOp, kIncClamp_StencilOp,
501 kAlways_StencilFunc, kAlways_StencilFunc,
502 0xffffffff, 0xffffffff,
503 0x00000000, 0x00000000,
504 0xffffffff, 0xffffffff,
505 };
506 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000507 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000508 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000509 this->drawSimpleRect(clip.getRect(c), NULL, 0);
510 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000511 if (canRenderDirectToStencil) {
512 this->setStencil(gDrawToStencil);
reed@google.com07f3ee12011-05-16 17:21:57 +0000513 pr->drawPath(this, 0, *clipPath, NonInvertedFill(fill),
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000514 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000515 } else {
reed@google.com07f3ee12011-05-16 17:21:57 +0000516 pr->drawPathToStencil(this, *clipPath,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000517 NonInvertedFill(fill),
518 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000519 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000520 }
521 }
522
523 // now we modify the clip bit by rendering either the clip
524 // element directly or a bounding rect of the entire clip.
525 this->enableState(kModifyStencilClip_StateBit);
526 for (int p = 0; p < passes; ++p) {
527 this->setStencil(stencilSettings[p]);
528 if (canDrawDirectToClip) {
529 if (kRect_ClipType == clip.getElementType(c)) {
530 SET_RANDOM_COLOR
531 this->drawSimpleRect(clip.getRect(c), NULL, 0);
532 } else {
533 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000534 GrAssert(!IsFillInverted(fill));
reed@google.com07f3ee12011-05-16 17:21:57 +0000535 pr->drawPath(this, 0, *clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000536 }
537 } else {
538 SET_RANDOM_COLOR
thakis@chromium.org441d7da2011-06-07 04:03:17 +0000539 this->drawSimpleRect(bounds, NULL, 0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000540 }
541 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000542 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000543 fClip = clip;
544 // recusive draws would have disabled this.
545 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000546 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000547
reed@google.comac10a2d2010-12-22 21:39:39 +0000548 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000549 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000550
reed@google.comac10a2d2010-12-22 21:39:39 +0000551 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000552 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000553 return false;
554 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000555 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000556 return true;
557}
558
reed@google.com07f3ee12011-05-16 17:21:57 +0000559GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000560 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000561 if (NULL != fClientPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000562 fClientPathRenderer->canDrawPath(this, path, fill)) {
563 return fClientPathRenderer;
564 } else {
565 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000566 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000567 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
568 this->supportsStencilWrapOps());
569 }
570 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
571 return fDefaultPathRenderer;
572 }
573}
574
575
bsalomon@google.comd302f142011-03-03 13:54:13 +0000576////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000577
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000578void GrGpu::geometrySourceWillPush() {
579 const GeometrySrcState& geoSrc = this->getGeomSrc();
580 if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
581 kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
582 this->finalizeReservedVertices();
583 }
584 if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
585 kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
586 this->finalizeReservedIndices();
587 }
588 GeometryPoolState& newState = fGeomPoolStateStack.push_back();
589#if GR_DEBUG
590 newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
591 newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
592 newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
593 newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
594#endif
595}
596
597void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
598 // if popping last entry then pops are unbalanced with pushes
599 GrAssert(fGeomPoolStateStack.count() > 1);
600 fGeomPoolStateStack.pop_back();
601}
602
603void GrGpu::onDrawIndexed(GrPrimitiveType type,
604 int startVertex,
605 int startIndex,
606 int vertexCount,
607 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000608
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000609 this->handleDirtyContext();
610
611 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000612 return;
613 }
614
615#if GR_COLLECT_STATS
616 fStats.fVertexCnt += vertexCount;
617 fStats.fIndexCnt += indexCount;
618 fStats.fDrawCnt += 1;
619#endif
620
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000621 int sVertex = startVertex;
622 int sIndex = startIndex;
623 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000624
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000625 this->onGpuDrawIndexed(type, sVertex, sIndex,
626 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000627}
628
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000629void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000630 int startVertex,
631 int vertexCount) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000632 this->handleDirtyContext();
633
634 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000635 return;
636 }
637#if GR_COLLECT_STATS
638 fStats.fVertexCnt += vertexCount;
639 fStats.fDrawCnt += 1;
640#endif
641
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000642 int sVertex = startVertex;
643 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000644
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000645 this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000646}
647
648void GrGpu::finalizeReservedVertices() {
649 GrAssert(NULL != fVertexPool);
650 fVertexPool->unlock();
651}
652
653void GrGpu::finalizeReservedIndices() {
654 GrAssert(NULL != fIndexPool);
655 fIndexPool->unlock();
656}
657
658void GrGpu::prepareVertexPool() {
659 if (NULL == fVertexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000660 GrAssert(0 == fVertexPoolUseCnt);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000661 fVertexPool = new GrVertexBufferAllocPool(this, true,
662 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000663 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000664 fVertexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000665 } else if (!fVertexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000666 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000667 fVertexPool->reset();
668 }
669}
670
671void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000672 if (NULL == fIndexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000673 GrAssert(0 == fIndexPoolUseCnt);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000674 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000675 fIndexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000676 } else if (!fIndexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000677 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000678 fIndexPool->reset();
679 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000680}
681
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000682bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
683 int vertexCount,
684 void** vertices) {
685 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
686
687 GrAssert(vertexCount > 0);
688 GrAssert(NULL != vertices);
689
690 this->prepareVertexPool();
691
692 *vertices = fVertexPool->makeSpace(vertexLayout,
693 vertexCount,
694 &geomPoolState.fPoolVertexBuffer,
695 &geomPoolState.fPoolStartVertex);
696 if (NULL == *vertices) {
697 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000698 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000699 ++fVertexPoolUseCnt;
reed@google.comac10a2d2010-12-22 21:39:39 +0000700 return true;
701}
702
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000703bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
704 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
705
706 GrAssert(indexCount > 0);
707 GrAssert(NULL != indices);
708
709 this->prepareIndexPool();
710
711 *indices = fIndexPool->makeSpace(indexCount,
712 &geomPoolState.fPoolIndexBuffer,
713 &geomPoolState.fPoolStartIndex);
714 if (NULL == *indices) {
715 return false;
716 }
717 ++fIndexPoolUseCnt;
718 return true;
719}
720
721void GrGpu::releaseReservedVertexSpace() {
722 const GeometrySrcState& geoSrc = this->getGeomSrc();
723 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
724 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
725 fVertexPool->putBack(bytes);
726 --fVertexPoolUseCnt;
727}
728
729void GrGpu::releaseReservedIndexSpace() {
730 const GeometrySrcState& geoSrc = this->getGeomSrc();
731 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
732 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
733 fIndexPool->putBack(bytes);
734 --fIndexPoolUseCnt;
735}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000736
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000737void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000738 this->prepareVertexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000739 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000740#if GR_DEBUG
741 bool success =
742#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000743 fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000744 vertexCount,
745 vertexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000746 &geomPoolState.fPoolVertexBuffer,
747 &geomPoolState.fPoolStartVertex);
748 ++fVertexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000749 GR_DEBUGASSERT(success);
750}
751
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000752void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000753 this->prepareIndexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000754 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000755#if GR_DEBUG
756 bool success =
757#endif
758 fIndexPool->appendIndices(indexCount,
759 indexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000760 &geomPoolState.fPoolIndexBuffer,
761 &geomPoolState.fPoolStartIndex);
762 ++fIndexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000763 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000764}
765
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000766void GrGpu::releaseVertexArray() {
767 // if vertex source was array, we stowed data in the pool
768 const GeometrySrcState& geoSrc = this->getGeomSrc();
769 GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
770 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
771 fVertexPool->putBack(bytes);
772 --fVertexPoolUseCnt;
773}
774
775void GrGpu::releaseIndexArray() {
776 // if index source was array, we stowed data in the pool
777 const GeometrySrcState& geoSrc = this->getGeomSrc();
778 GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
779 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
780 fIndexPool->putBack(bytes);
781 --fIndexPoolUseCnt;
782}
783
bsalomon@google.comd302f142011-03-03 13:54:13 +0000784////////////////////////////////////////////////////////////////////////////////
785
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000786const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000787 return fStats;
788}
789
790void GrGpu::resetStats() {
791 memset(&fStats, 0, sizeof(fStats));
792}
793
794void GrGpu::printStats() const {
795 if (GR_COLLECT_STATS) {
796 GrPrintf(
797 "-v-------------------------GPU STATS----------------------------v-\n"
798 "Stats collection is: %s\n"
799 "Draws: %04d, Verts: %04d, Indices: %04d\n"
800 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
801 "TexCreates: %04d, RTCreates:%04d\n"
802 "-^--------------------------------------------------------------^-\n",
803 (GR_COLLECT_STATS ? "ON" : "OFF"),
804 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
805 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
806 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
807 }
808}
809
810////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000811const GrSamplerState GrSamplerState::gClampNoFilter(
812 GrSamplerState::kClamp_WrapMode,
813 GrSamplerState::kClamp_WrapMode,
814 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000815 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000816 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000817
818
819
820