blob: c89dd4e4bb34b5e1cce1bc65d66949124f8e4970 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@google.comac10a2d2010-12-22 21:39:39 +000010#include "GrGpu.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000011#include "GrTextStrike.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000012#include "GrClipIterator.h"
13#include "GrIndexBuffer.h"
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000014#include "GrVertexBuffer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000015#include "GrBufferAllocPool.h"
bsalomon@google.comd302f142011-03-03 13:54:13 +000016#include "GrPathRenderer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000017
18// probably makes no sense for this to be less than a page
bsalomon@google.comee435122011-07-01 14:57:55 +000019static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
20static const int VERTEX_POOL_VB_COUNT = 4;
bsalomon@google.com25fd36c2011-07-06 17:41:08 +000021static const size_t INDEX_POOL_IB_SIZE = 1 << 16;
22static const int INDEX_POOL_IB_COUNT = 4;
reed@google.comac10a2d2010-12-22 21:39:39 +000023
bsalomon@google.comd302f142011-03-03 13:54:13 +000024////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000025
26extern void gr_run_unittests();
27
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000028#define DEBUG_INVAL_BUFFER 0xdeadcafe
29#define DEBUG_INVAL_START_IDX -1
30
bsalomon@google.com8fe72472011-03-30 21:26:44 +000031GrGpu::GrGpu()
32 : f8bitPaletteSupport(false)
bsalomon@google.com669fdc42011-04-05 17:08:27 +000033 , fContext(NULL)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000034 , fVertexPool(NULL)
35 , fIndexPool(NULL)
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000036 , fVertexPoolUseCnt(0)
37 , fIndexPoolUseCnt(0)
38 , fGeomPoolStateStack(&fGeoSrcStateStackStorage)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000039 , fQuadIndexBuffer(NULL)
40 , fUnitSquareVertexBuffer(NULL)
41 , fDefaultPathRenderer(NULL)
42 , fClientPathRenderer(NULL)
43 , fContextIsDirty(true)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000044 , fResourceHead(NULL) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +000045
reed@google.comac10a2d2010-12-22 21:39:39 +000046#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000047 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000048#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000049
50 fGeomPoolStateStack.push_back();
51#if GR_DEBUG
52 GeometryPoolState& poolState = fGeomPoolStateStack.back();
53 poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
54 poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
55 poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
56 poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
57#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000058 resetStats();
59}
60
61GrGpu::~GrGpu() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 releaseResources();
reed@google.comac10a2d2010-12-22 21:39:39 +000063}
64
bsalomon@google.com8fe72472011-03-30 21:26:44 +000065void GrGpu::abandonResources() {
66
67 while (NULL != fResourceHead) {
68 fResourceHead->abandon();
69 }
70
71 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
72 GrAssert(NULL == fUnitSquareVertexBuffer ||
73 !fUnitSquareVertexBuffer->isValid());
74 GrSafeSetNull(fQuadIndexBuffer);
75 GrSafeSetNull(fUnitSquareVertexBuffer);
76 delete fVertexPool;
77 fVertexPool = NULL;
78 delete fIndexPool;
79 fIndexPool = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000080}
81
bsalomon@google.com8fe72472011-03-30 21:26:44 +000082void GrGpu::releaseResources() {
83
84 while (NULL != fResourceHead) {
85 fResourceHead->release();
86 }
87
88 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
89 GrAssert(NULL == fUnitSquareVertexBuffer ||
90 !fUnitSquareVertexBuffer->isValid());
91 GrSafeSetNull(fQuadIndexBuffer);
92 GrSafeSetNull(fUnitSquareVertexBuffer);
93 delete fVertexPool;
94 fVertexPool = NULL;
95 delete fIndexPool;
96 fIndexPool = NULL;
97}
98
99void GrGpu::insertResource(GrResource* resource) {
100 GrAssert(NULL != resource);
101 GrAssert(this == resource->getGpu());
102 GrAssert(NULL == resource->fNext);
103 GrAssert(NULL == resource->fPrevious);
104
105 resource->fNext = fResourceHead;
106 if (NULL != fResourceHead) {
107 GrAssert(NULL == fResourceHead->fPrevious);
108 fResourceHead->fPrevious = resource;
109 }
110 fResourceHead = resource;
111}
112
113void GrGpu::removeResource(GrResource* resource) {
114 GrAssert(NULL != resource);
115 GrAssert(NULL != fResourceHead);
116
117 if (fResourceHead == resource) {
118 GrAssert(NULL == resource->fPrevious);
119 fResourceHead = resource->fNext;
120 } else {
121 GrAssert(NULL != fResourceHead);
122 resource->fPrevious->fNext = resource->fNext;
123 }
124 if (NULL != resource->fNext) {
125 resource->fNext->fPrevious = resource->fPrevious;
126 }
127 resource->fNext = NULL;
128 resource->fPrevious = NULL;
129}
130
131
reed@google.comac10a2d2010-12-22 21:39:39 +0000132void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000133#if GR_DEBUG
134 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
135#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000136}
137
bsalomon@google.comd302f142011-03-03 13:54:13 +0000138////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000139
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000140GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000141 const void* srcData, size_t rowBytes) {
142 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000143 return this->onCreateTexture(desc, srcData, rowBytes);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000144}
145
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000146GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
147 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000148 return this->onCreateRenderTargetFrom3DApiState();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000149}
150
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000151GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
152 this->handleDirtyContext();
153 return this->onCreatePlatformSurface(desc);
154}
155
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000156GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
157 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000158 return this->onCreateVertexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000159}
160
161GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
162 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000163 return this->onCreateIndexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000164}
165
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000166void GrGpu::clear(const GrIRect* rect, GrColor color) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000167 this->handleDirtyContext();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000168 this->onClear(rect, color);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000169}
170
171void GrGpu::forceRenderTargetFlush() {
172 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000173 this->onForceRenderTargetFlush();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000174}
175
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000176bool GrGpu::readPixels(GrRenderTarget* target,
177 int left, int top, int width, int height,
178 GrPixelConfig config, void* buffer) {
179
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000180 this->handleDirtyContext();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000181 return this->onReadPixels(target, left, top, width, height, config, buffer);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000182}
183
184////////////////////////////////////////////////////////////////////////////////
185
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000186static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000187
reed@google.com8195f672011-01-12 18:14:28 +0000188GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000189
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000190static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000191 for (int i = 0; i < quadCount; ++i) {
192 indices[6 * i + 0] = 4 * i + 0;
193 indices[6 * i + 1] = 4 * i + 1;
194 indices[6 * i + 2] = 4 * i + 2;
195 indices[6 * i + 3] = 4 * i + 0;
196 indices[6 * i + 4] = 4 * i + 2;
197 indices[6 * i + 5] = 4 * i + 3;
198 }
199}
200
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000201const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000202 if (NULL == fQuadIndexBuffer) {
203 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
204 GrGpu* me = const_cast<GrGpu*>(this);
205 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
206 if (NULL != fQuadIndexBuffer) {
207 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
208 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000209 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000210 fQuadIndexBuffer->unlock();
211 } else {
212 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000213 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000214 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
215 fQuadIndexBuffer->unref();
216 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000217 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000218 }
219 GrFree(indices);
220 }
221 }
222 }
223
224 return fQuadIndexBuffer;
225}
226
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000227const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000228 if (NULL == fUnitSquareVertexBuffer) {
229
230 static const GrPoint DATA[] = {
reed@google.com7744c202011-05-06 19:26:26 +0000231 { 0, 0 },
232 { GR_Scalar1, 0 },
233 { GR_Scalar1, GR_Scalar1 },
234 { 0, GR_Scalar1 }
235#if 0
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000236 GrPoint(0, 0),
237 GrPoint(GR_Scalar1,0),
238 GrPoint(GR_Scalar1,GR_Scalar1),
239 GrPoint(0, GR_Scalar1)
reed@google.com7744c202011-05-06 19:26:26 +0000240#endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000241 };
242 static const size_t SIZE = sizeof(DATA);
243
244 GrGpu* me = const_cast<GrGpu*>(this);
245 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
246 if (NULL != fUnitSquareVertexBuffer) {
247 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
248 fUnitSquareVertexBuffer->unref();
249 fUnitSquareVertexBuffer = NULL;
250 GrCrash("Can't get vertices into buffer!");
251 }
252 }
253 }
254
255 return fUnitSquareVertexBuffer;
256}
257
bsalomon@google.comd302f142011-03-03 13:54:13 +0000258////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000259
bsalomon@google.comd302f142011-03-03 13:54:13 +0000260// stencil settings to use when clip is in stencil
261const GrStencilSettings GrGpu::gClipStencilSettings = {
262 kKeep_StencilOp, kKeep_StencilOp,
263 kKeep_StencilOp, kKeep_StencilOp,
264 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
265 0, 0,
266 0, 0,
267 0, 0
268};
269
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000270// mapping of clip-respecting stencil funcs to normal stencil funcs
271// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000272static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
273 {// Stencil-Clipping is DISABLED, effectively always inside the clip
274 // In the Clip Funcs
275 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
276 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
277 kLess_StencilFunc, // kLessIfInClip_StencilFunc
278 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
279 // Special in the clip func that forces user's ref to be 0.
280 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
281 // make ref 0 and do normal nequal.
282 },
283 {// Stencil-Clipping is ENABLED
284 // In the Clip Funcs
285 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
286 // eq stencil clip bit, mask
287 // out user bits.
288
289 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
290 // add stencil bit to mask and ref
291
292 kLess_StencilFunc, // kLessIfInClip_StencilFunc
293 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
294 // for both of these we can add
295 // the clip bit to the mask and
296 // ref and compare as normal
297 // Special in the clip func that forces user's ref to be 0.
298 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
299 // make ref have only the clip bit set
300 // and make comparison be less
301 // 10..0 < 1..user_bits..
302 }
303};
304
305GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
306 GrAssert(func >= 0);
307 if (func >= kBasicStencilFuncCount) {
308 GrAssert(func < kStencilFuncCount);
309 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
310 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
311 }
312 return func;
313}
314
315void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
316 bool clipInStencil,
317 unsigned int clipBit,
318 unsigned int userBits,
319 unsigned int* ref,
320 unsigned int* mask) {
321 if (func < kBasicStencilFuncCount) {
322 *mask &= userBits;
323 *ref &= userBits;
324 } else {
325 if (clipInStencil) {
326 switch (func) {
327 case kAlwaysIfInClip_StencilFunc:
328 *mask = clipBit;
329 *ref = clipBit;
330 break;
331 case kEqualIfInClip_StencilFunc:
332 case kLessIfInClip_StencilFunc:
333 case kLEqualIfInClip_StencilFunc:
334 *mask = (*mask & userBits) | clipBit;
335 *ref = (*ref & userBits) | clipBit;
336 break;
337 case kNonZeroIfInClip_StencilFunc:
338 *mask = (*mask & userBits) | clipBit;
339 *ref = clipBit;
340 break;
341 default:
342 GrCrash("Unknown stencil func");
343 }
344 } else {
345 *mask &= userBits;
346 *ref &= userBits;
347 }
348 }
349}
350
351////////////////////////////////////////////////////////////////////////////////
352
353#define VISUALIZE_COMPLEX_CLIP 0
354
355#if VISUALIZE_COMPLEX_CLIP
356 #include "GrRandom.h"
357 GrRandom gRandom;
358 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
359#else
360 #define SET_RANDOM_COLOR
361#endif
362
bsalomon@google.comffca4002011-02-22 20:34:01 +0000363bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000364 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000365 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000366
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000367 // we check this early because we need a valid
368 // render target to setup stencil clipping
369 // before even going into flushGraphicsState
370 if (NULL == fCurrDrawState.fRenderTarget) {
371 GrAssert(!"No render target bound.");
372 return false;
373 }
374
reed@google.comac10a2d2010-12-22 21:39:39 +0000375 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000376 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
377
378 GrRect bounds;
379 GrRect rtRect;
380 rtRect.setLTRB(0, 0,
381 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000382 if (fClip.hasConservativeBounds()) {
383 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000384 if (!bounds.intersect(rtRect)) {
385 bounds.setEmpty();
386 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000387 } else {
388 bounds = rtRect;
389 }
390
391 bounds.roundOut(&clipRect);
392 if (clipRect.isEmpty()) {
393 clipRect.setLTRB(0,0,0,0);
394 }
395 r = &clipRect;
396
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000397 // use the stencil clip if we can't represent the clip as a rectangle.
398 fClipInStencil = !fClip.isRect() && !fClip.isEmpty() &&
399 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000400
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000401 if (fClipInStencil &&
402 fClip != rt.fLastStencilClip) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000403
404 rt.fLastStencilClip = fClip;
405 // we set the current clip to the bounds so that our recursive
406 // draws are scissored to them. We use the copy of the complex clip
407 // in the rt to render
408 const GrClip& clip = rt.fLastStencilClip;
409 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000410
411 AutoStateRestore asr(this);
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000412 AutoGeometryPush agp(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000413
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000414 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000415 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000416 this->flushScissor(NULL);
417#if !VISUALIZE_COMPLEX_CLIP
418 this->enableState(kNoColorWrites_StateBit);
419#else
420 this->disableState(kNoColorWrites_StateBit);
421#endif
422 int count = clip.getElementCount();
423 int clipBit = rt.stencilBits();
424 clipBit = (1 << (clipBit-1));
425
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000426 // often we'll see the first two elements of the clip are
427 // the full rt size and another element intersected with it.
428 // We can skip the first full-size rect and save a big rect draw.
429 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000430 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000431 kRect_ClipType == clip.getElementType(0) &&
432 kIntersect_SetOp == clip.getOp(1)&&
433 clip.getRect(0).contains(bounds)) {
434 firstElement = 1;
435 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000436
bsalomon@google.comd302f142011-03-03 13:54:13 +0000437 // walk through each clip element and perform its set op
438 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000439 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000440 GrPathFill fill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000441 bool fillInverted;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000442 // enabled at bottom of loop
443 this->disableState(kModifyStencilClip_StateBit);
444
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000445 bool canRenderDirectToStencil; // can the clip element be drawn
446 // directly to the stencil buffer
447 // with a non-inverted fill rule
448 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000449 // resolve in/out status.
450
451 GrPathRenderer* pr = NULL;
reed@google.com07f3ee12011-05-16 17:21:57 +0000452 const GrPath* clipPath = NULL;
bsalomon@google.comee435122011-07-01 14:57:55 +0000453 GrPathRenderer::AutoClearPath arp;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000454 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000455 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000456 fill = kEvenOdd_PathFill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000457 fillInverted = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000458 } else {
459 fill = clip.getPathFill(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000460 fillInverted = IsFillInverted(fill);
461 fill = NonInvertedFill(fill);
reed@google.com07f3ee12011-05-16 17:21:57 +0000462 clipPath = &clip.getPath(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000463 pr = this->getClipPathRenderer(*clipPath, fill);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000464 canRenderDirectToStencil =
bsalomon@google.comee435122011-07-01 14:57:55 +0000465 !pr->requiresStencilPass(this, *clipPath, fill);
466 arp.set(pr, this, clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000467 }
468
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000469 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000470 int passes;
471 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
472
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000473 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000474 // fill rule, and set operation can
475 // we render the element directly to
476 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000477 canDrawDirectToClip =
478 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000479 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000480 clipBit,
bsalomon@google.comee435122011-07-01 14:57:55 +0000481 fillInverted,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000482 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000483
484 // draw the element to the client stencil bits if necessary
485 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000486 static const GrStencilSettings gDrawToStencil = {
487 kIncClamp_StencilOp, kIncClamp_StencilOp,
488 kIncClamp_StencilOp, kIncClamp_StencilOp,
489 kAlways_StencilFunc, kAlways_StencilFunc,
490 0xffffffff, 0xffffffff,
491 0x00000000, 0x00000000,
492 0xffffffff, 0xffffffff,
493 };
494 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000495 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000496 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000497 this->drawSimpleRect(clip.getRect(c), NULL, 0);
498 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000499 if (canRenderDirectToStencil) {
500 this->setStencil(gDrawToStencil);
bsalomon@google.comee435122011-07-01 14:57:55 +0000501 pr->drawPath(0);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000502 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000503 pr->drawPathToStencil();
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000504 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000505 }
506 }
507
508 // now we modify the clip bit by rendering either the clip
509 // element directly or a bounding rect of the entire clip.
510 this->enableState(kModifyStencilClip_StateBit);
511 for (int p = 0; p < passes; ++p) {
512 this->setStencil(stencilSettings[p]);
513 if (canDrawDirectToClip) {
514 if (kRect_ClipType == clip.getElementType(c)) {
515 SET_RANDOM_COLOR
516 this->drawSimpleRect(clip.getRect(c), NULL, 0);
517 } else {
518 SET_RANDOM_COLOR
bsalomon@google.comee435122011-07-01 14:57:55 +0000519 pr->drawPath(0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000520 }
521 } else {
522 SET_RANDOM_COLOR
thakis@chromium.org441d7da2011-06-07 04:03:17 +0000523 this->drawSimpleRect(bounds, NULL, 0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000524 }
525 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000526 }
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000527 // restore clip
bsalomon@google.comd302f142011-03-03 13:54:13 +0000528 fClip = clip;
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000529 // recusive draws would have disabled this since they drew with
530 // the clip bounds as clip.
531 fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000532 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000533 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000534
reed@google.comac10a2d2010-12-22 21:39:39 +0000535 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000536 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000537 return false;
538 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000539 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000540 return true;
541}
542
reed@google.com07f3ee12011-05-16 17:21:57 +0000543GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000544 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000545 if (NULL != fClientPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +0000546 fClientPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000547 return fClientPathRenderer;
548 } else {
549 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000550 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000551 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
552 this->supportsStencilWrapOps());
553 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000554 GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000555 return fDefaultPathRenderer;
556 }
557}
558
559
bsalomon@google.comd302f142011-03-03 13:54:13 +0000560////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000561
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000562void GrGpu::geometrySourceWillPush() {
563 const GeometrySrcState& geoSrc = this->getGeomSrc();
564 if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
565 kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
566 this->finalizeReservedVertices();
567 }
568 if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
569 kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
570 this->finalizeReservedIndices();
571 }
572 GeometryPoolState& newState = fGeomPoolStateStack.push_back();
573#if GR_DEBUG
574 newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
575 newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
576 newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
577 newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
578#endif
579}
580
581void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
582 // if popping last entry then pops are unbalanced with pushes
583 GrAssert(fGeomPoolStateStack.count() > 1);
584 fGeomPoolStateStack.pop_back();
585}
586
587void GrGpu::onDrawIndexed(GrPrimitiveType type,
588 int startVertex,
589 int startIndex,
590 int vertexCount,
591 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000592
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000593 this->handleDirtyContext();
594
595 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000596 return;
597 }
598
599#if GR_COLLECT_STATS
600 fStats.fVertexCnt += vertexCount;
601 fStats.fIndexCnt += indexCount;
602 fStats.fDrawCnt += 1;
603#endif
604
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000605 int sVertex = startVertex;
606 int sIndex = startIndex;
607 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000608
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000609 this->onGpuDrawIndexed(type, sVertex, sIndex,
610 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000611}
612
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000613void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000614 int startVertex,
615 int vertexCount) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000616 this->handleDirtyContext();
617
618 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000619 return;
620 }
621#if GR_COLLECT_STATS
622 fStats.fVertexCnt += vertexCount;
623 fStats.fDrawCnt += 1;
624#endif
625
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000626 int sVertex = startVertex;
627 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000628
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000629 this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000630}
631
632void GrGpu::finalizeReservedVertices() {
633 GrAssert(NULL != fVertexPool);
634 fVertexPool->unlock();
635}
636
637void GrGpu::finalizeReservedIndices() {
638 GrAssert(NULL != fIndexPool);
639 fIndexPool->unlock();
640}
641
642void GrGpu::prepareVertexPool() {
643 if (NULL == fVertexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000644 GrAssert(0 == fVertexPoolUseCnt);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000645 fVertexPool = new GrVertexBufferAllocPool(this, true,
646 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000647 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000648 fVertexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000649 } else if (!fVertexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000650 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000651 fVertexPool->reset();
652 }
653}
654
655void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000656 if (NULL == fIndexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000657 GrAssert(0 == fIndexPoolUseCnt);
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000658 fIndexPool = new GrIndexBufferAllocPool(this, true,
659 INDEX_POOL_IB_SIZE,
660 INDEX_POOL_IB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000661 fIndexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000662 } else if (!fIndexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000663 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000664 fIndexPool->reset();
665 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000666}
667
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000668bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
669 int vertexCount,
670 void** vertices) {
671 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
672
673 GrAssert(vertexCount > 0);
674 GrAssert(NULL != vertices);
675
676 this->prepareVertexPool();
677
678 *vertices = fVertexPool->makeSpace(vertexLayout,
679 vertexCount,
680 &geomPoolState.fPoolVertexBuffer,
681 &geomPoolState.fPoolStartVertex);
682 if (NULL == *vertices) {
683 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000684 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000685 ++fVertexPoolUseCnt;
reed@google.comac10a2d2010-12-22 21:39:39 +0000686 return true;
687}
688
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000689bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
690 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
691
692 GrAssert(indexCount > 0);
693 GrAssert(NULL != indices);
694
695 this->prepareIndexPool();
696
697 *indices = fIndexPool->makeSpace(indexCount,
698 &geomPoolState.fPoolIndexBuffer,
699 &geomPoolState.fPoolStartIndex);
700 if (NULL == *indices) {
701 return false;
702 }
703 ++fIndexPoolUseCnt;
704 return true;
705}
706
707void GrGpu::releaseReservedVertexSpace() {
708 const GeometrySrcState& geoSrc = this->getGeomSrc();
709 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
710 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
711 fVertexPool->putBack(bytes);
712 --fVertexPoolUseCnt;
713}
714
715void GrGpu::releaseReservedIndexSpace() {
716 const GeometrySrcState& geoSrc = this->getGeomSrc();
717 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
718 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
719 fIndexPool->putBack(bytes);
720 --fIndexPoolUseCnt;
721}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000722
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000723void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000724 this->prepareVertexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000725 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000726#if GR_DEBUG
727 bool success =
728#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000729 fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000730 vertexCount,
731 vertexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000732 &geomPoolState.fPoolVertexBuffer,
733 &geomPoolState.fPoolStartVertex);
734 ++fVertexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000735 GR_DEBUGASSERT(success);
736}
737
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000738void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000739 this->prepareIndexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000740 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000741#if GR_DEBUG
742 bool success =
743#endif
744 fIndexPool->appendIndices(indexCount,
745 indexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000746 &geomPoolState.fPoolIndexBuffer,
747 &geomPoolState.fPoolStartIndex);
748 ++fIndexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000749 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000750}
751
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000752void GrGpu::releaseVertexArray() {
753 // if vertex source was array, we stowed data in the pool
754 const GeometrySrcState& geoSrc = this->getGeomSrc();
755 GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
756 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
757 fVertexPool->putBack(bytes);
758 --fVertexPoolUseCnt;
759}
760
761void GrGpu::releaseIndexArray() {
762 // if index source was array, we stowed data in the pool
763 const GeometrySrcState& geoSrc = this->getGeomSrc();
764 GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
765 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
766 fIndexPool->putBack(bytes);
767 --fIndexPoolUseCnt;
768}
769
bsalomon@google.comd302f142011-03-03 13:54:13 +0000770////////////////////////////////////////////////////////////////////////////////
771
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000772const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000773 return fStats;
774}
775
776void GrGpu::resetStats() {
777 memset(&fStats, 0, sizeof(fStats));
778}
779
780void GrGpu::printStats() const {
781 if (GR_COLLECT_STATS) {
782 GrPrintf(
783 "-v-------------------------GPU STATS----------------------------v-\n"
784 "Stats collection is: %s\n"
785 "Draws: %04d, Verts: %04d, Indices: %04d\n"
786 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
787 "TexCreates: %04d, RTCreates:%04d\n"
788 "-^--------------------------------------------------------------^-\n",
789 (GR_COLLECT_STATS ? "ON" : "OFF"),
790 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
791 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
792 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
793 }
794}
795
796////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000797const GrSamplerState GrSamplerState::gClampNoFilter(
798 GrSamplerState::kClamp_WrapMode,
799 GrSamplerState::kClamp_WrapMode,
800 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000801 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000802 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000803
804
805
806