blob: 10307e3baf8729dda7c327e3dc1419872db18588 [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"
reed@google.comac10a2d2010-12-22 21:39:39 +000019#include "GrClipIterator.h"
20#include "GrIndexBuffer.h"
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000021#include "GrVertexBuffer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000022#include "GrBufferAllocPool.h"
bsalomon@google.comd302f142011-03-03 13:54:13 +000023#include "GrPathRenderer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000024
25// probably makes no sense for this to be less than a page
bsalomon@google.comee435122011-07-01 14:57:55 +000026static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
27static const int VERTEX_POOL_VB_COUNT = 4;
bsalomon@google.com25fd36c2011-07-06 17:41:08 +000028static const size_t INDEX_POOL_IB_SIZE = 1 << 16;
29static const int INDEX_POOL_IB_COUNT = 4;
reed@google.comac10a2d2010-12-22 21:39:39 +000030
bsalomon@google.comd302f142011-03-03 13:54:13 +000031////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000032
33extern void gr_run_unittests();
34
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000035#define DEBUG_INVAL_BUFFER 0xdeadcafe
36#define DEBUG_INVAL_START_IDX -1
37
bsalomon@google.com8fe72472011-03-30 21:26:44 +000038GrGpu::GrGpu()
39 : f8bitPaletteSupport(false)
bsalomon@google.com669fdc42011-04-05 17:08:27 +000040 , fContext(NULL)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000041 , fVertexPool(NULL)
42 , fIndexPool(NULL)
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000043 , fVertexPoolUseCnt(0)
44 , fIndexPoolUseCnt(0)
45 , fGeomPoolStateStack(&fGeoSrcStateStackStorage)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000046 , fQuadIndexBuffer(NULL)
47 , fUnitSquareVertexBuffer(NULL)
48 , fDefaultPathRenderer(NULL)
49 , fClientPathRenderer(NULL)
50 , fContextIsDirty(true)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000051 , fResourceHead(NULL) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +000052
reed@google.comac10a2d2010-12-22 21:39:39 +000053#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000054 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000055#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000056
57 fGeomPoolStateStack.push_back();
58#if GR_DEBUG
59 GeometryPoolState& poolState = fGeomPoolStateStack.back();
60 poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
61 poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
62 poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
63 poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
64#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000065 resetStats();
66}
67
68GrGpu::~GrGpu() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000069 releaseResources();
reed@google.comac10a2d2010-12-22 21:39:39 +000070}
71
bsalomon@google.com8fe72472011-03-30 21:26:44 +000072void GrGpu::abandonResources() {
73
74 while (NULL != fResourceHead) {
75 fResourceHead->abandon();
76 }
77
78 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
79 GrAssert(NULL == fUnitSquareVertexBuffer ||
80 !fUnitSquareVertexBuffer->isValid());
81 GrSafeSetNull(fQuadIndexBuffer);
82 GrSafeSetNull(fUnitSquareVertexBuffer);
83 delete fVertexPool;
84 fVertexPool = NULL;
85 delete fIndexPool;
86 fIndexPool = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000087}
88
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089void GrGpu::releaseResources() {
90
91 while (NULL != fResourceHead) {
92 fResourceHead->release();
93 }
94
95 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
96 GrAssert(NULL == fUnitSquareVertexBuffer ||
97 !fUnitSquareVertexBuffer->isValid());
98 GrSafeSetNull(fQuadIndexBuffer);
99 GrSafeSetNull(fUnitSquareVertexBuffer);
100 delete fVertexPool;
101 fVertexPool = NULL;
102 delete fIndexPool;
103 fIndexPool = NULL;
104}
105
106void GrGpu::insertResource(GrResource* resource) {
107 GrAssert(NULL != resource);
108 GrAssert(this == resource->getGpu());
109 GrAssert(NULL == resource->fNext);
110 GrAssert(NULL == resource->fPrevious);
111
112 resource->fNext = fResourceHead;
113 if (NULL != fResourceHead) {
114 GrAssert(NULL == fResourceHead->fPrevious);
115 fResourceHead->fPrevious = resource;
116 }
117 fResourceHead = resource;
118}
119
120void GrGpu::removeResource(GrResource* resource) {
121 GrAssert(NULL != resource);
122 GrAssert(NULL != fResourceHead);
123
124 if (fResourceHead == resource) {
125 GrAssert(NULL == resource->fPrevious);
126 fResourceHead = resource->fNext;
127 } else {
128 GrAssert(NULL != fResourceHead);
129 resource->fPrevious->fNext = resource->fNext;
130 }
131 if (NULL != resource->fNext) {
132 resource->fNext->fPrevious = resource->fPrevious;
133 }
134 resource->fNext = NULL;
135 resource->fPrevious = NULL;
136}
137
138
reed@google.comac10a2d2010-12-22 21:39:39 +0000139void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000140#if GR_DEBUG
141 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
142#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000143}
144
bsalomon@google.comd302f142011-03-03 13:54:13 +0000145////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000146
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000147GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000148 const void* srcData, size_t rowBytes) {
149 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000150 return this->onCreateTexture(desc, srcData, rowBytes);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000151}
152
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000153GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
154 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000155 return this->onCreateRenderTargetFrom3DApiState();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000156}
157
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000158GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
159 this->handleDirtyContext();
160 return this->onCreatePlatformSurface(desc);
161}
162
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000163GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
164 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000165 return this->onCreateVertexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000166}
167
168GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
169 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000170 return this->onCreateIndexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000171}
172
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000173void GrGpu::clear(const GrIRect* rect, GrColor color) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000174 this->handleDirtyContext();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000175 this->onClear(rect, color);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000176}
177
178void GrGpu::forceRenderTargetFlush() {
179 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000180 this->onForceRenderTargetFlush();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000181}
182
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000183bool GrGpu::readPixels(GrRenderTarget* target,
184 int left, int top, int width, int height,
185 GrPixelConfig config, void* buffer) {
186
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000187 this->handleDirtyContext();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000188 return this->onReadPixels(target, left, top, width, height, config, buffer);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000189}
190
191////////////////////////////////////////////////////////////////////////////////
192
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000193static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000194
reed@google.com8195f672011-01-12 18:14:28 +0000195GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000196
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000197static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000198 for (int i = 0; i < quadCount; ++i) {
199 indices[6 * i + 0] = 4 * i + 0;
200 indices[6 * i + 1] = 4 * i + 1;
201 indices[6 * i + 2] = 4 * i + 2;
202 indices[6 * i + 3] = 4 * i + 0;
203 indices[6 * i + 4] = 4 * i + 2;
204 indices[6 * i + 5] = 4 * i + 3;
205 }
206}
207
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000208const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000209 if (NULL == fQuadIndexBuffer) {
210 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
211 GrGpu* me = const_cast<GrGpu*>(this);
212 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
213 if (NULL != fQuadIndexBuffer) {
214 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
215 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000216 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000217 fQuadIndexBuffer->unlock();
218 } else {
219 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000220 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000221 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
222 fQuadIndexBuffer->unref();
223 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000224 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000225 }
226 GrFree(indices);
227 }
228 }
229 }
230
231 return fQuadIndexBuffer;
232}
233
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000234const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000235 if (NULL == fUnitSquareVertexBuffer) {
236
237 static const GrPoint DATA[] = {
reed@google.com7744c202011-05-06 19:26:26 +0000238 { 0, 0 },
239 { GR_Scalar1, 0 },
240 { GR_Scalar1, GR_Scalar1 },
241 { 0, GR_Scalar1 }
242#if 0
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000243 GrPoint(0, 0),
244 GrPoint(GR_Scalar1,0),
245 GrPoint(GR_Scalar1,GR_Scalar1),
246 GrPoint(0, GR_Scalar1)
reed@google.com7744c202011-05-06 19:26:26 +0000247#endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000248 };
249 static const size_t SIZE = sizeof(DATA);
250
251 GrGpu* me = const_cast<GrGpu*>(this);
252 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
253 if (NULL != fUnitSquareVertexBuffer) {
254 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
255 fUnitSquareVertexBuffer->unref();
256 fUnitSquareVertexBuffer = NULL;
257 GrCrash("Can't get vertices into buffer!");
258 }
259 }
260 }
261
262 return fUnitSquareVertexBuffer;
263}
264
bsalomon@google.comd302f142011-03-03 13:54:13 +0000265////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000266
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000267void GrGpu::clipWillBeSet(const GrClip& newClip) {
268 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000269 fClipState.fClipIsDirty = true;
270 }
271}
272
bsalomon@google.comd302f142011-03-03 13:54:13 +0000273////////////////////////////////////////////////////////////////////////////////
274
275// stencil settings to use when clip is in stencil
276const GrStencilSettings GrGpu::gClipStencilSettings = {
277 kKeep_StencilOp, kKeep_StencilOp,
278 kKeep_StencilOp, kKeep_StencilOp,
279 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
280 0, 0,
281 0, 0,
282 0, 0
283};
284
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000285// mapping of clip-respecting stencil funcs to normal stencil funcs
286// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000287static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
288 {// Stencil-Clipping is DISABLED, effectively always inside the clip
289 // In the Clip Funcs
290 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
291 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
292 kLess_StencilFunc, // kLessIfInClip_StencilFunc
293 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
294 // Special in the clip func that forces user's ref to be 0.
295 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
296 // make ref 0 and do normal nequal.
297 },
298 {// Stencil-Clipping is ENABLED
299 // In the Clip Funcs
300 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
301 // eq stencil clip bit, mask
302 // out user bits.
303
304 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
305 // add stencil bit to mask and ref
306
307 kLess_StencilFunc, // kLessIfInClip_StencilFunc
308 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
309 // for both of these we can add
310 // the clip bit to the mask and
311 // ref and compare as normal
312 // Special in the clip func that forces user's ref to be 0.
313 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
314 // make ref have only the clip bit set
315 // and make comparison be less
316 // 10..0 < 1..user_bits..
317 }
318};
319
320GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
321 GrAssert(func >= 0);
322 if (func >= kBasicStencilFuncCount) {
323 GrAssert(func < kStencilFuncCount);
324 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
325 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
326 }
327 return func;
328}
329
330void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
331 bool clipInStencil,
332 unsigned int clipBit,
333 unsigned int userBits,
334 unsigned int* ref,
335 unsigned int* mask) {
336 if (func < kBasicStencilFuncCount) {
337 *mask &= userBits;
338 *ref &= userBits;
339 } else {
340 if (clipInStencil) {
341 switch (func) {
342 case kAlwaysIfInClip_StencilFunc:
343 *mask = clipBit;
344 *ref = clipBit;
345 break;
346 case kEqualIfInClip_StencilFunc:
347 case kLessIfInClip_StencilFunc:
348 case kLEqualIfInClip_StencilFunc:
349 *mask = (*mask & userBits) | clipBit;
350 *ref = (*ref & userBits) | clipBit;
351 break;
352 case kNonZeroIfInClip_StencilFunc:
353 *mask = (*mask & userBits) | clipBit;
354 *ref = clipBit;
355 break;
356 default:
357 GrCrash("Unknown stencil func");
358 }
359 } else {
360 *mask &= userBits;
361 *ref &= userBits;
362 }
363 }
364}
365
366////////////////////////////////////////////////////////////////////////////////
367
368#define VISUALIZE_COMPLEX_CLIP 0
369
370#if VISUALIZE_COMPLEX_CLIP
371 #include "GrRandom.h"
372 GrRandom gRandom;
373 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
374#else
375 #define SET_RANDOM_COLOR
376#endif
377
bsalomon@google.comffca4002011-02-22 20:34:01 +0000378bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000379 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000380 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000381
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000382 // we check this early because we need a valid
383 // render target to setup stencil clipping
384 // before even going into flushGraphicsState
385 if (NULL == fCurrDrawState.fRenderTarget) {
386 GrAssert(!"No render target bound.");
387 return false;
388 }
389
reed@google.comac10a2d2010-12-22 21:39:39 +0000390 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000391 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
392
393 GrRect bounds;
394 GrRect rtRect;
395 rtRect.setLTRB(0, 0,
396 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000397 if (fClip.hasConservativeBounds()) {
398 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000399 if (!bounds.intersect(rtRect)) {
400 bounds.setEmpty();
401 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000402 } else {
403 bounds = rtRect;
404 }
405
406 bounds.roundOut(&clipRect);
407 if (clipRect.isEmpty()) {
408 clipRect.setLTRB(0,0,0,0);
409 }
410 r = &clipRect;
411
412 fClipState.fClipInStencil = !fClip.isRect() &&
413 !fClip.isEmpty() &&
414 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000415
416 if (fClipState.fClipInStencil &&
417 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000418 fClip != rt.fLastStencilClip)) {
419
420 rt.fLastStencilClip = fClip;
421 // we set the current clip to the bounds so that our recursive
422 // draws are scissored to them. We use the copy of the complex clip
423 // in the rt to render
424 const GrClip& clip = rt.fLastStencilClip;
425 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000426
427 AutoStateRestore asr(this);
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000428 AutoGeometryPush agp(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000429
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000430 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000431 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000432 this->flushScissor(NULL);
433#if !VISUALIZE_COMPLEX_CLIP
434 this->enableState(kNoColorWrites_StateBit);
435#else
436 this->disableState(kNoColorWrites_StateBit);
437#endif
438 int count = clip.getElementCount();
439 int clipBit = rt.stencilBits();
440 clipBit = (1 << (clipBit-1));
441
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000442 // often we'll see the first two elements of the clip are
443 // the full rt size and another element intersected with it.
444 // We can skip the first full-size rect and save a big rect draw.
445 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000446 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000447 kRect_ClipType == clip.getElementType(0) &&
448 kIntersect_SetOp == clip.getOp(1)&&
449 clip.getRect(0).contains(bounds)) {
450 firstElement = 1;
451 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000452
bsalomon@google.comd302f142011-03-03 13:54:13 +0000453 // walk through each clip element and perform its set op
454 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000455 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000456 GrPathFill fill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000457 bool fillInverted;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000458 // 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.comee435122011-07-01 14:57:55 +0000469 GrPathRenderer::AutoClearPath arp;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000470 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000471 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000472 fill = kEvenOdd_PathFill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000473 fillInverted = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000474 } else {
475 fill = clip.getPathFill(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000476 fillInverted = IsFillInverted(fill);
477 fill = NonInvertedFill(fill);
reed@google.com07f3ee12011-05-16 17:21:57 +0000478 clipPath = &clip.getPath(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000479 pr = this->getClipPathRenderer(*clipPath, fill);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000480 canRenderDirectToStencil =
bsalomon@google.comee435122011-07-01 14:57:55 +0000481 !pr->requiresStencilPass(this, *clipPath, fill);
482 arp.set(pr, this, clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000483 }
484
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000485 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000486 int passes;
487 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
488
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000489 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000490 // fill rule, and set operation can
491 // we render the element directly to
492 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000493 canDrawDirectToClip =
494 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000495 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000496 clipBit,
bsalomon@google.comee435122011-07-01 14:57:55 +0000497 fillInverted,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000498 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000499
500 // draw the element to the client stencil bits if necessary
501 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000502 static const GrStencilSettings gDrawToStencil = {
503 kIncClamp_StencilOp, kIncClamp_StencilOp,
504 kIncClamp_StencilOp, kIncClamp_StencilOp,
505 kAlways_StencilFunc, kAlways_StencilFunc,
506 0xffffffff, 0xffffffff,
507 0x00000000, 0x00000000,
508 0xffffffff, 0xffffffff,
509 };
510 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000511 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000512 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000513 this->drawSimpleRect(clip.getRect(c), NULL, 0);
514 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000515 if (canRenderDirectToStencil) {
516 this->setStencil(gDrawToStencil);
bsalomon@google.comee435122011-07-01 14:57:55 +0000517 pr->drawPath(0);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000518 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000519 pr->drawPathToStencil();
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000520 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000521 }
522 }
523
524 // now we modify the clip bit by rendering either the clip
525 // element directly or a bounding rect of the entire clip.
526 this->enableState(kModifyStencilClip_StateBit);
527 for (int p = 0; p < passes; ++p) {
528 this->setStencil(stencilSettings[p]);
529 if (canDrawDirectToClip) {
530 if (kRect_ClipType == clip.getElementType(c)) {
531 SET_RANDOM_COLOR
532 this->drawSimpleRect(clip.getRect(c), NULL, 0);
533 } else {
534 SET_RANDOM_COLOR
bsalomon@google.comee435122011-07-01 14:57:55 +0000535 pr->drawPath(0);
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.comee435122011-07-01 14:57:55 +0000562 fClientPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000563 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 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000570 GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000571 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.com25fd36c2011-07-06 17:41:08 +0000674 fIndexPool = new GrIndexBufferAllocPool(this, true,
675 INDEX_POOL_IB_SIZE,
676 INDEX_POOL_IB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000677 fIndexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000678 } else if (!fIndexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000679 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000680 fIndexPool->reset();
681 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000682}
683
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000684bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
685 int vertexCount,
686 void** vertices) {
687 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
688
689 GrAssert(vertexCount > 0);
690 GrAssert(NULL != vertices);
691
692 this->prepareVertexPool();
693
694 *vertices = fVertexPool->makeSpace(vertexLayout,
695 vertexCount,
696 &geomPoolState.fPoolVertexBuffer,
697 &geomPoolState.fPoolStartVertex);
698 if (NULL == *vertices) {
699 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000700 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000701 ++fVertexPoolUseCnt;
reed@google.comac10a2d2010-12-22 21:39:39 +0000702 return true;
703}
704
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000705bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
706 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
707
708 GrAssert(indexCount > 0);
709 GrAssert(NULL != indices);
710
711 this->prepareIndexPool();
712
713 *indices = fIndexPool->makeSpace(indexCount,
714 &geomPoolState.fPoolIndexBuffer,
715 &geomPoolState.fPoolStartIndex);
716 if (NULL == *indices) {
717 return false;
718 }
719 ++fIndexPoolUseCnt;
720 return true;
721}
722
723void GrGpu::releaseReservedVertexSpace() {
724 const GeometrySrcState& geoSrc = this->getGeomSrc();
725 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
726 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
727 fVertexPool->putBack(bytes);
728 --fVertexPoolUseCnt;
729}
730
731void GrGpu::releaseReservedIndexSpace() {
732 const GeometrySrcState& geoSrc = this->getGeomSrc();
733 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
734 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
735 fIndexPool->putBack(bytes);
736 --fIndexPoolUseCnt;
737}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000738
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000739void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000740 this->prepareVertexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000741 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000742#if GR_DEBUG
743 bool success =
744#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000745 fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000746 vertexCount,
747 vertexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000748 &geomPoolState.fPoolVertexBuffer,
749 &geomPoolState.fPoolStartVertex);
750 ++fVertexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000751 GR_DEBUGASSERT(success);
752}
753
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000754void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000755 this->prepareIndexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000756 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000757#if GR_DEBUG
758 bool success =
759#endif
760 fIndexPool->appendIndices(indexCount,
761 indexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000762 &geomPoolState.fPoolIndexBuffer,
763 &geomPoolState.fPoolStartIndex);
764 ++fIndexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000765 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000766}
767
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000768void GrGpu::releaseVertexArray() {
769 // if vertex source was array, we stowed data in the pool
770 const GeometrySrcState& geoSrc = this->getGeomSrc();
771 GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
772 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
773 fVertexPool->putBack(bytes);
774 --fVertexPoolUseCnt;
775}
776
777void GrGpu::releaseIndexArray() {
778 // if index source was array, we stowed data in the pool
779 const GeometrySrcState& geoSrc = this->getGeomSrc();
780 GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
781 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
782 fIndexPool->putBack(bytes);
783 --fIndexPoolUseCnt;
784}
785
bsalomon@google.comd302f142011-03-03 13:54:13 +0000786////////////////////////////////////////////////////////////////////////////////
787
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000788const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000789 return fStats;
790}
791
792void GrGpu::resetStats() {
793 memset(&fStats, 0, sizeof(fStats));
794}
795
796void GrGpu::printStats() const {
797 if (GR_COLLECT_STATS) {
798 GrPrintf(
799 "-v-------------------------GPU STATS----------------------------v-\n"
800 "Stats collection is: %s\n"
801 "Draws: %04d, Verts: %04d, Indices: %04d\n"
802 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
803 "TexCreates: %04d, RTCreates:%04d\n"
804 "-^--------------------------------------------------------------^-\n",
805 (GR_COLLECT_STATS ? "ON" : "OFF"),
806 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
807 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
808 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
809 }
810}
811
812////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000813const GrSamplerState GrSamplerState::gClampNoFilter(
814 GrSamplerState::kClamp_WrapMode,
815 GrSamplerState::kClamp_WrapMode,
816 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000817 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000818 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000819
820
821
822