blob: 62c96f524a4ae6e6edb01c6895ec95dcb70340e5 [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;
reed@google.comac10a2d2010-12-22 21:39:39 +000029
bsalomon@google.comd302f142011-03-03 13:54:13 +000030////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000031
32extern void gr_run_unittests();
33
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000034#define DEBUG_INVAL_BUFFER 0xdeadcafe
35#define DEBUG_INVAL_START_IDX -1
36
bsalomon@google.com8fe72472011-03-30 21:26:44 +000037GrGpu::GrGpu()
38 : f8bitPaletteSupport(false)
bsalomon@google.com669fdc42011-04-05 17:08:27 +000039 , fContext(NULL)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000040 , fVertexPool(NULL)
41 , fIndexPool(NULL)
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000042 , fVertexPoolUseCnt(0)
43 , fIndexPoolUseCnt(0)
44 , fGeomPoolStateStack(&fGeoSrcStateStackStorage)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000045 , fQuadIndexBuffer(NULL)
46 , fUnitSquareVertexBuffer(NULL)
47 , fDefaultPathRenderer(NULL)
48 , fClientPathRenderer(NULL)
49 , fContextIsDirty(true)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000050 , fResourceHead(NULL) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +000051
reed@google.comac10a2d2010-12-22 21:39:39 +000052#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000053 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000054#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000055
56 fGeomPoolStateStack.push_back();
57#if GR_DEBUG
58 GeometryPoolState& poolState = fGeomPoolStateStack.back();
59 poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
60 poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
61 poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
62 poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
63#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000064 resetStats();
65}
66
67GrGpu::~GrGpu() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000068 releaseResources();
reed@google.comac10a2d2010-12-22 21:39:39 +000069}
70
bsalomon@google.com8fe72472011-03-30 21:26:44 +000071void GrGpu::abandonResources() {
72
73 while (NULL != fResourceHead) {
74 fResourceHead->abandon();
75 }
76
77 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
78 GrAssert(NULL == fUnitSquareVertexBuffer ||
79 !fUnitSquareVertexBuffer->isValid());
80 GrSafeSetNull(fQuadIndexBuffer);
81 GrSafeSetNull(fUnitSquareVertexBuffer);
82 delete fVertexPool;
83 fVertexPool = NULL;
84 delete fIndexPool;
85 fIndexPool = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000086}
87
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088void GrGpu::releaseResources() {
89
90 while (NULL != fResourceHead) {
91 fResourceHead->release();
92 }
93
94 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
95 GrAssert(NULL == fUnitSquareVertexBuffer ||
96 !fUnitSquareVertexBuffer->isValid());
97 GrSafeSetNull(fQuadIndexBuffer);
98 GrSafeSetNull(fUnitSquareVertexBuffer);
99 delete fVertexPool;
100 fVertexPool = NULL;
101 delete fIndexPool;
102 fIndexPool = NULL;
103}
104
105void GrGpu::insertResource(GrResource* resource) {
106 GrAssert(NULL != resource);
107 GrAssert(this == resource->getGpu());
108 GrAssert(NULL == resource->fNext);
109 GrAssert(NULL == resource->fPrevious);
110
111 resource->fNext = fResourceHead;
112 if (NULL != fResourceHead) {
113 GrAssert(NULL == fResourceHead->fPrevious);
114 fResourceHead->fPrevious = resource;
115 }
116 fResourceHead = resource;
117}
118
119void GrGpu::removeResource(GrResource* resource) {
120 GrAssert(NULL != resource);
121 GrAssert(NULL != fResourceHead);
122
123 if (fResourceHead == resource) {
124 GrAssert(NULL == resource->fPrevious);
125 fResourceHead = resource->fNext;
126 } else {
127 GrAssert(NULL != fResourceHead);
128 resource->fPrevious->fNext = resource->fNext;
129 }
130 if (NULL != resource->fNext) {
131 resource->fNext->fPrevious = resource->fPrevious;
132 }
133 resource->fNext = NULL;
134 resource->fPrevious = NULL;
135}
136
137
reed@google.comac10a2d2010-12-22 21:39:39 +0000138void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000139#if GR_DEBUG
140 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
141#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000142}
143
bsalomon@google.comd302f142011-03-03 13:54:13 +0000144////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000145
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000146GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000147 const void* srcData, size_t rowBytes) {
148 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000149 return this->onCreateTexture(desc, srcData, rowBytes);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000150}
151
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000152GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
153 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000154 return this->onCreateRenderTargetFrom3DApiState();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000155}
156
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000157GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
158 this->handleDirtyContext();
159 return this->onCreatePlatformSurface(desc);
160}
161
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000162GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
163 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000164 return this->onCreateVertexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000165}
166
167GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
168 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000169 return this->onCreateIndexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000170}
171
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000172void GrGpu::clear(const GrIRect* rect, GrColor color) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000173 this->handleDirtyContext();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000174 this->onClear(rect, color);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000175}
176
177void GrGpu::forceRenderTargetFlush() {
178 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000179 this->onForceRenderTargetFlush();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000180}
181
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000182bool GrGpu::readPixels(GrRenderTarget* target,
183 int left, int top, int width, int height,
184 GrPixelConfig config, void* buffer) {
185
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000186 this->handleDirtyContext();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000187 return this->onReadPixels(target, left, top, width, height, config, buffer);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000188}
189
190////////////////////////////////////////////////////////////////////////////////
191
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000192static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000193
reed@google.com8195f672011-01-12 18:14:28 +0000194GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000195
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000196static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000197 for (int i = 0; i < quadCount; ++i) {
198 indices[6 * i + 0] = 4 * i + 0;
199 indices[6 * i + 1] = 4 * i + 1;
200 indices[6 * i + 2] = 4 * i + 2;
201 indices[6 * i + 3] = 4 * i + 0;
202 indices[6 * i + 4] = 4 * i + 2;
203 indices[6 * i + 5] = 4 * i + 3;
204 }
205}
206
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000207const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000208 if (NULL == fQuadIndexBuffer) {
209 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
210 GrGpu* me = const_cast<GrGpu*>(this);
211 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
212 if (NULL != fQuadIndexBuffer) {
213 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
214 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000215 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000216 fQuadIndexBuffer->unlock();
217 } else {
218 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000219 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000220 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
221 fQuadIndexBuffer->unref();
222 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000223 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000224 }
225 GrFree(indices);
226 }
227 }
228 }
229
230 return fQuadIndexBuffer;
231}
232
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000233const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000234 if (NULL == fUnitSquareVertexBuffer) {
235
236 static const GrPoint DATA[] = {
reed@google.com7744c202011-05-06 19:26:26 +0000237 { 0, 0 },
238 { GR_Scalar1, 0 },
239 { GR_Scalar1, GR_Scalar1 },
240 { 0, GR_Scalar1 }
241#if 0
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000242 GrPoint(0, 0),
243 GrPoint(GR_Scalar1,0),
244 GrPoint(GR_Scalar1,GR_Scalar1),
245 GrPoint(0, GR_Scalar1)
reed@google.com7744c202011-05-06 19:26:26 +0000246#endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000247 };
248 static const size_t SIZE = sizeof(DATA);
249
250 GrGpu* me = const_cast<GrGpu*>(this);
251 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
252 if (NULL != fUnitSquareVertexBuffer) {
253 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
254 fUnitSquareVertexBuffer->unref();
255 fUnitSquareVertexBuffer = NULL;
256 GrCrash("Can't get vertices into buffer!");
257 }
258 }
259 }
260
261 return fUnitSquareVertexBuffer;
262}
263
bsalomon@google.comd302f142011-03-03 13:54:13 +0000264////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000265
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000266void GrGpu::clipWillBeSet(const GrClip& newClip) {
267 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000268 fClipState.fClipIsDirty = true;
269 }
270}
271
bsalomon@google.comd302f142011-03-03 13:54:13 +0000272////////////////////////////////////////////////////////////////////////////////
273
274// stencil settings to use when clip is in stencil
275const GrStencilSettings GrGpu::gClipStencilSettings = {
276 kKeep_StencilOp, kKeep_StencilOp,
277 kKeep_StencilOp, kKeep_StencilOp,
278 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
279 0, 0,
280 0, 0,
281 0, 0
282};
283
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000284// mapping of clip-respecting stencil funcs to normal stencil funcs
285// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000286static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
287 {// Stencil-Clipping is DISABLED, effectively always inside the clip
288 // In the Clip Funcs
289 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
290 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
291 kLess_StencilFunc, // kLessIfInClip_StencilFunc
292 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
293 // Special in the clip func that forces user's ref to be 0.
294 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
295 // make ref 0 and do normal nequal.
296 },
297 {// Stencil-Clipping is ENABLED
298 // In the Clip Funcs
299 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
300 // eq stencil clip bit, mask
301 // out user bits.
302
303 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
304 // add stencil bit to mask and ref
305
306 kLess_StencilFunc, // kLessIfInClip_StencilFunc
307 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
308 // for both of these we can add
309 // the clip bit to the mask and
310 // ref and compare as normal
311 // Special in the clip func that forces user's ref to be 0.
312 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
313 // make ref have only the clip bit set
314 // and make comparison be less
315 // 10..0 < 1..user_bits..
316 }
317};
318
319GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
320 GrAssert(func >= 0);
321 if (func >= kBasicStencilFuncCount) {
322 GrAssert(func < kStencilFuncCount);
323 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
324 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
325 }
326 return func;
327}
328
329void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
330 bool clipInStencil,
331 unsigned int clipBit,
332 unsigned int userBits,
333 unsigned int* ref,
334 unsigned int* mask) {
335 if (func < kBasicStencilFuncCount) {
336 *mask &= userBits;
337 *ref &= userBits;
338 } else {
339 if (clipInStencil) {
340 switch (func) {
341 case kAlwaysIfInClip_StencilFunc:
342 *mask = clipBit;
343 *ref = clipBit;
344 break;
345 case kEqualIfInClip_StencilFunc:
346 case kLessIfInClip_StencilFunc:
347 case kLEqualIfInClip_StencilFunc:
348 *mask = (*mask & userBits) | clipBit;
349 *ref = (*ref & userBits) | clipBit;
350 break;
351 case kNonZeroIfInClip_StencilFunc:
352 *mask = (*mask & userBits) | clipBit;
353 *ref = clipBit;
354 break;
355 default:
356 GrCrash("Unknown stencil func");
357 }
358 } else {
359 *mask &= userBits;
360 *ref &= userBits;
361 }
362 }
363}
364
365////////////////////////////////////////////////////////////////////////////////
366
367#define VISUALIZE_COMPLEX_CLIP 0
368
369#if VISUALIZE_COMPLEX_CLIP
370 #include "GrRandom.h"
371 GrRandom gRandom;
372 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
373#else
374 #define SET_RANDOM_COLOR
375#endif
376
bsalomon@google.comffca4002011-02-22 20:34:01 +0000377bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000378 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000379 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000380
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000381 // we check this early because we need a valid
382 // render target to setup stencil clipping
383 // before even going into flushGraphicsState
384 if (NULL == fCurrDrawState.fRenderTarget) {
385 GrAssert(!"No render target bound.");
386 return false;
387 }
388
reed@google.comac10a2d2010-12-22 21:39:39 +0000389 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000390 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
391
392 GrRect bounds;
393 GrRect rtRect;
394 rtRect.setLTRB(0, 0,
395 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000396 if (fClip.hasConservativeBounds()) {
397 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000398 if (!bounds.intersect(rtRect)) {
399 bounds.setEmpty();
400 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000401 } else {
402 bounds = rtRect;
403 }
404
405 bounds.roundOut(&clipRect);
406 if (clipRect.isEmpty()) {
407 clipRect.setLTRB(0,0,0,0);
408 }
409 r = &clipRect;
410
411 fClipState.fClipInStencil = !fClip.isRect() &&
412 !fClip.isEmpty() &&
413 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000414
415 if (fClipState.fClipInStencil &&
416 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000417 fClip != rt.fLastStencilClip)) {
418
419 rt.fLastStencilClip = fClip;
420 // we set the current clip to the bounds so that our recursive
421 // draws are scissored to them. We use the copy of the complex clip
422 // in the rt to render
423 const GrClip& clip = rt.fLastStencilClip;
424 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000425
426 AutoStateRestore asr(this);
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000427 AutoGeometryPush agp(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000428
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000429 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000430 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000431 this->flushScissor(NULL);
432#if !VISUALIZE_COMPLEX_CLIP
433 this->enableState(kNoColorWrites_StateBit);
434#else
435 this->disableState(kNoColorWrites_StateBit);
436#endif
437 int count = clip.getElementCount();
438 int clipBit = rt.stencilBits();
439 clipBit = (1 << (clipBit-1));
440
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000441 // often we'll see the first two elements of the clip are
442 // the full rt size and another element intersected with it.
443 // We can skip the first full-size rect and save a big rect draw.
444 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000445 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000446 kRect_ClipType == clip.getElementType(0) &&
447 kIntersect_SetOp == clip.getOp(1)&&
448 clip.getRect(0).contains(bounds)) {
449 firstElement = 1;
450 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000451
bsalomon@google.comd302f142011-03-03 13:54:13 +0000452 // walk through each clip element and perform its set op
453 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000454 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000455 GrPathFill fill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000456 bool fillInverted;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000457 // enabled at bottom of loop
458 this->disableState(kModifyStencilClip_StateBit);
459
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000460 bool canRenderDirectToStencil; // can the clip element be drawn
461 // directly to the stencil buffer
462 // with a non-inverted fill rule
463 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000464 // resolve in/out status.
465
466 GrPathRenderer* pr = NULL;
reed@google.com07f3ee12011-05-16 17:21:57 +0000467 const GrPath* clipPath = NULL;
bsalomon@google.comee435122011-07-01 14:57:55 +0000468 GrPathRenderer::AutoClearPath arp;
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;
bsalomon@google.comee435122011-07-01 14:57:55 +0000472 fillInverted = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000473 } else {
474 fill = clip.getPathFill(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000475 fillInverted = IsFillInverted(fill);
476 fill = NonInvertedFill(fill);
reed@google.com07f3ee12011-05-16 17:21:57 +0000477 clipPath = &clip.getPath(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000478 pr = this->getClipPathRenderer(*clipPath, fill);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000479 canRenderDirectToStencil =
bsalomon@google.comee435122011-07-01 14:57:55 +0000480 !pr->requiresStencilPass(this, *clipPath, fill);
481 arp.set(pr, this, clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000482 }
483
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000484 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000485 int passes;
486 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
487
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000488 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000489 // fill rule, and set operation can
490 // we render the element directly to
491 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000492 canDrawDirectToClip =
493 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000494 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000495 clipBit,
bsalomon@google.comee435122011-07-01 14:57:55 +0000496 fillInverted,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000497 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000498
499 // draw the element to the client stencil bits if necessary
500 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000501 static const GrStencilSettings gDrawToStencil = {
502 kIncClamp_StencilOp, kIncClamp_StencilOp,
503 kIncClamp_StencilOp, kIncClamp_StencilOp,
504 kAlways_StencilFunc, kAlways_StencilFunc,
505 0xffffffff, 0xffffffff,
506 0x00000000, 0x00000000,
507 0xffffffff, 0xffffffff,
508 };
509 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000510 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000511 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000512 this->drawSimpleRect(clip.getRect(c), NULL, 0);
513 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000514 if (canRenderDirectToStencil) {
515 this->setStencil(gDrawToStencil);
bsalomon@google.comee435122011-07-01 14:57:55 +0000516 pr->drawPath(0);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000517 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000518 pr->drawPathToStencil();
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.comee435122011-07-01 14:57:55 +0000534 pr->drawPath(0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000535 }
536 } else {
537 SET_RANDOM_COLOR
thakis@chromium.org441d7da2011-06-07 04:03:17 +0000538 this->drawSimpleRect(bounds, NULL, 0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000539 }
540 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000541 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000542 fClip = clip;
543 // recusive draws would have disabled this.
544 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000545 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000546
reed@google.comac10a2d2010-12-22 21:39:39 +0000547 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000548 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000549
reed@google.comac10a2d2010-12-22 21:39:39 +0000550 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000551 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000552 return false;
553 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000554 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000555 return true;
556}
557
reed@google.com07f3ee12011-05-16 17:21:57 +0000558GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000559 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000560 if (NULL != fClientPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +0000561 fClientPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000562 return fClientPathRenderer;
563 } else {
564 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000565 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000566 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
567 this->supportsStencilWrapOps());
568 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000569 GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000570 return fDefaultPathRenderer;
571 }
572}
573
574
bsalomon@google.comd302f142011-03-03 13:54:13 +0000575////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000576
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000577void GrGpu::geometrySourceWillPush() {
578 const GeometrySrcState& geoSrc = this->getGeomSrc();
579 if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
580 kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
581 this->finalizeReservedVertices();
582 }
583 if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
584 kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
585 this->finalizeReservedIndices();
586 }
587 GeometryPoolState& newState = fGeomPoolStateStack.push_back();
588#if GR_DEBUG
589 newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
590 newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
591 newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
592 newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
593#endif
594}
595
596void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
597 // if popping last entry then pops are unbalanced with pushes
598 GrAssert(fGeomPoolStateStack.count() > 1);
599 fGeomPoolStateStack.pop_back();
600}
601
602void GrGpu::onDrawIndexed(GrPrimitiveType type,
603 int startVertex,
604 int startIndex,
605 int vertexCount,
606 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000607
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000608 this->handleDirtyContext();
609
610 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000611 return;
612 }
613
614#if GR_COLLECT_STATS
615 fStats.fVertexCnt += vertexCount;
616 fStats.fIndexCnt += indexCount;
617 fStats.fDrawCnt += 1;
618#endif
619
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000620 int sVertex = startVertex;
621 int sIndex = startIndex;
622 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000623
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000624 this->onGpuDrawIndexed(type, sVertex, sIndex,
625 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000626}
627
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000628void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000629 int startVertex,
630 int vertexCount) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000631 this->handleDirtyContext();
632
633 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000634 return;
635 }
636#if GR_COLLECT_STATS
637 fStats.fVertexCnt += vertexCount;
638 fStats.fDrawCnt += 1;
639#endif
640
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000641 int sVertex = startVertex;
642 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000643
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000644 this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000645}
646
647void GrGpu::finalizeReservedVertices() {
648 GrAssert(NULL != fVertexPool);
649 fVertexPool->unlock();
650}
651
652void GrGpu::finalizeReservedIndices() {
653 GrAssert(NULL != fIndexPool);
654 fIndexPool->unlock();
655}
656
657void GrGpu::prepareVertexPool() {
658 if (NULL == fVertexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000659 GrAssert(0 == fVertexPoolUseCnt);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000660 fVertexPool = new GrVertexBufferAllocPool(this, true,
661 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000662 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000663 fVertexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000664 } else if (!fVertexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000665 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000666 fVertexPool->reset();
667 }
668}
669
670void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000671 if (NULL == fIndexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000672 GrAssert(0 == fIndexPoolUseCnt);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000673 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000674 fIndexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000675 } else if (!fIndexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000676 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000677 fIndexPool->reset();
678 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000679}
680
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000681bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
682 int vertexCount,
683 void** vertices) {
684 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
685
686 GrAssert(vertexCount > 0);
687 GrAssert(NULL != vertices);
688
689 this->prepareVertexPool();
690
691 *vertices = fVertexPool->makeSpace(vertexLayout,
692 vertexCount,
693 &geomPoolState.fPoolVertexBuffer,
694 &geomPoolState.fPoolStartVertex);
695 if (NULL == *vertices) {
696 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000697 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000698 ++fVertexPoolUseCnt;
reed@google.comac10a2d2010-12-22 21:39:39 +0000699 return true;
700}
701
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000702bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
703 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
704
705 GrAssert(indexCount > 0);
706 GrAssert(NULL != indices);
707
708 this->prepareIndexPool();
709
710 *indices = fIndexPool->makeSpace(indexCount,
711 &geomPoolState.fPoolIndexBuffer,
712 &geomPoolState.fPoolStartIndex);
713 if (NULL == *indices) {
714 return false;
715 }
716 ++fIndexPoolUseCnt;
717 return true;
718}
719
720void GrGpu::releaseReservedVertexSpace() {
721 const GeometrySrcState& geoSrc = this->getGeomSrc();
722 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
723 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
724 fVertexPool->putBack(bytes);
725 --fVertexPoolUseCnt;
726}
727
728void GrGpu::releaseReservedIndexSpace() {
729 const GeometrySrcState& geoSrc = this->getGeomSrc();
730 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
731 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
732 fIndexPool->putBack(bytes);
733 --fIndexPoolUseCnt;
734}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000735
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000736void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000737 this->prepareVertexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000738 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000739#if GR_DEBUG
740 bool success =
741#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000742 fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000743 vertexCount,
744 vertexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000745 &geomPoolState.fPoolVertexBuffer,
746 &geomPoolState.fPoolStartVertex);
747 ++fVertexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000748 GR_DEBUGASSERT(success);
749}
750
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000751void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000752 this->prepareIndexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000753 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000754#if GR_DEBUG
755 bool success =
756#endif
757 fIndexPool->appendIndices(indexCount,
758 indexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000759 &geomPoolState.fPoolIndexBuffer,
760 &geomPoolState.fPoolStartIndex);
761 ++fIndexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000762 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000763}
764
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000765void GrGpu::releaseVertexArray() {
766 // if vertex source was array, we stowed data in the pool
767 const GeometrySrcState& geoSrc = this->getGeomSrc();
768 GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
769 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
770 fVertexPool->putBack(bytes);
771 --fVertexPoolUseCnt;
772}
773
774void GrGpu::releaseIndexArray() {
775 // if index source was array, we stowed data in the pool
776 const GeometrySrcState& geoSrc = this->getGeomSrc();
777 GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
778 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
779 fIndexPool->putBack(bytes);
780 --fIndexPoolUseCnt;
781}
782
bsalomon@google.comd302f142011-03-03 13:54:13 +0000783////////////////////////////////////////////////////////////////////////////////
784
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000785const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000786 return fStats;
787}
788
789void GrGpu::resetStats() {
790 memset(&fStats, 0, sizeof(fStats));
791}
792
793void GrGpu::printStats() const {
794 if (GR_COLLECT_STATS) {
795 GrPrintf(
796 "-v-------------------------GPU STATS----------------------------v-\n"
797 "Stats collection is: %s\n"
798 "Draws: %04d, Verts: %04d, Indices: %04d\n"
799 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
800 "TexCreates: %04d, RTCreates:%04d\n"
801 "-^--------------------------------------------------------------^-\n",
802 (GR_COLLECT_STATS ? "ON" : "OFF"),
803 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
804 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
805 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
806 }
807}
808
809////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000810const GrSamplerState GrSamplerState::gClampNoFilter(
811 GrSamplerState::kClamp_WrapMode,
812 GrSamplerState::kClamp_WrapMode,
813 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000814 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000815 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000816
817
818
819