blob: 011d39d58ee653543e2ddcb3e6e9bd3125134dd7 [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.com86afc2a2011-02-16 16:12:19 +0000260void GrGpu::clipWillBeSet(const GrClip& newClip) {
261 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000262 fClipState.fClipIsDirty = true;
263 }
264}
265
bsalomon@google.comd302f142011-03-03 13:54:13 +0000266////////////////////////////////////////////////////////////////////////////////
267
268// stencil settings to use when clip is in stencil
269const GrStencilSettings GrGpu::gClipStencilSettings = {
270 kKeep_StencilOp, kKeep_StencilOp,
271 kKeep_StencilOp, kKeep_StencilOp,
272 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
273 0, 0,
274 0, 0,
275 0, 0
276};
277
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000278// mapping of clip-respecting stencil funcs to normal stencil funcs
279// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000280static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
281 {// Stencil-Clipping is DISABLED, effectively always inside the clip
282 // In the Clip Funcs
283 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
284 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
285 kLess_StencilFunc, // kLessIfInClip_StencilFunc
286 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
287 // Special in the clip func that forces user's ref to be 0.
288 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
289 // make ref 0 and do normal nequal.
290 },
291 {// Stencil-Clipping is ENABLED
292 // In the Clip Funcs
293 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
294 // eq stencil clip bit, mask
295 // out user bits.
296
297 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
298 // add stencil bit to mask and ref
299
300 kLess_StencilFunc, // kLessIfInClip_StencilFunc
301 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
302 // for both of these we can add
303 // the clip bit to the mask and
304 // ref and compare as normal
305 // Special in the clip func that forces user's ref to be 0.
306 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
307 // make ref have only the clip bit set
308 // and make comparison be less
309 // 10..0 < 1..user_bits..
310 }
311};
312
313GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
314 GrAssert(func >= 0);
315 if (func >= kBasicStencilFuncCount) {
316 GrAssert(func < kStencilFuncCount);
317 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
318 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
319 }
320 return func;
321}
322
323void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
324 bool clipInStencil,
325 unsigned int clipBit,
326 unsigned int userBits,
327 unsigned int* ref,
328 unsigned int* mask) {
329 if (func < kBasicStencilFuncCount) {
330 *mask &= userBits;
331 *ref &= userBits;
332 } else {
333 if (clipInStencil) {
334 switch (func) {
335 case kAlwaysIfInClip_StencilFunc:
336 *mask = clipBit;
337 *ref = clipBit;
338 break;
339 case kEqualIfInClip_StencilFunc:
340 case kLessIfInClip_StencilFunc:
341 case kLEqualIfInClip_StencilFunc:
342 *mask = (*mask & userBits) | clipBit;
343 *ref = (*ref & userBits) | clipBit;
344 break;
345 case kNonZeroIfInClip_StencilFunc:
346 *mask = (*mask & userBits) | clipBit;
347 *ref = clipBit;
348 break;
349 default:
350 GrCrash("Unknown stencil func");
351 }
352 } else {
353 *mask &= userBits;
354 *ref &= userBits;
355 }
356 }
357}
358
359////////////////////////////////////////////////////////////////////////////////
360
361#define VISUALIZE_COMPLEX_CLIP 0
362
363#if VISUALIZE_COMPLEX_CLIP
364 #include "GrRandom.h"
365 GrRandom gRandom;
366 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
367#else
368 #define SET_RANDOM_COLOR
369#endif
370
bsalomon@google.comffca4002011-02-22 20:34:01 +0000371bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000372 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000373 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000374
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000375 // we check this early because we need a valid
376 // render target to setup stencil clipping
377 // before even going into flushGraphicsState
378 if (NULL == fCurrDrawState.fRenderTarget) {
379 GrAssert(!"No render target bound.");
380 return false;
381 }
382
reed@google.comac10a2d2010-12-22 21:39:39 +0000383 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000384 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
385
386 GrRect bounds;
387 GrRect rtRect;
388 rtRect.setLTRB(0, 0,
389 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000390 if (fClip.hasConservativeBounds()) {
391 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000392 if (!bounds.intersect(rtRect)) {
393 bounds.setEmpty();
394 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000395 } else {
396 bounds = rtRect;
397 }
398
399 bounds.roundOut(&clipRect);
400 if (clipRect.isEmpty()) {
401 clipRect.setLTRB(0,0,0,0);
402 }
403 r = &clipRect;
404
405 fClipState.fClipInStencil = !fClip.isRect() &&
406 !fClip.isEmpty() &&
407 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000408
409 if (fClipState.fClipInStencil &&
410 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000411 fClip != rt.fLastStencilClip)) {
412
413 rt.fLastStencilClip = fClip;
414 // we set the current clip to the bounds so that our recursive
415 // draws are scissored to them. We use the copy of the complex clip
416 // in the rt to render
417 const GrClip& clip = rt.fLastStencilClip;
418 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000419
420 AutoStateRestore asr(this);
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000421 AutoGeometryPush agp(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000422
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000423 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000424 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000425 this->flushScissor(NULL);
426#if !VISUALIZE_COMPLEX_CLIP
427 this->enableState(kNoColorWrites_StateBit);
428#else
429 this->disableState(kNoColorWrites_StateBit);
430#endif
431 int count = clip.getElementCount();
432 int clipBit = rt.stencilBits();
433 clipBit = (1 << (clipBit-1));
434
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000435 // often we'll see the first two elements of the clip are
436 // the full rt size and another element intersected with it.
437 // We can skip the first full-size rect and save a big rect draw.
438 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000439 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000440 kRect_ClipType == clip.getElementType(0) &&
441 kIntersect_SetOp == clip.getOp(1)&&
442 clip.getRect(0).contains(bounds)) {
443 firstElement = 1;
444 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000445
bsalomon@google.comd302f142011-03-03 13:54:13 +0000446 // walk through each clip element and perform its set op
447 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000448 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000449 GrPathFill fill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000450 bool fillInverted;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000451 // enabled at bottom of loop
452 this->disableState(kModifyStencilClip_StateBit);
453
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000454 bool canRenderDirectToStencil; // can the clip element be drawn
455 // directly to the stencil buffer
456 // with a non-inverted fill rule
457 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000458 // resolve in/out status.
459
460 GrPathRenderer* pr = NULL;
reed@google.com07f3ee12011-05-16 17:21:57 +0000461 const GrPath* clipPath = NULL;
bsalomon@google.comee435122011-07-01 14:57:55 +0000462 GrPathRenderer::AutoClearPath arp;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000463 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000464 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000465 fill = kEvenOdd_PathFill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000466 fillInverted = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000467 } else {
468 fill = clip.getPathFill(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000469 fillInverted = IsFillInverted(fill);
470 fill = NonInvertedFill(fill);
reed@google.com07f3ee12011-05-16 17:21:57 +0000471 clipPath = &clip.getPath(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000472 pr = this->getClipPathRenderer(*clipPath, fill);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000473 canRenderDirectToStencil =
bsalomon@google.comee435122011-07-01 14:57:55 +0000474 !pr->requiresStencilPass(this, *clipPath, fill);
475 arp.set(pr, this, clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000476 }
477
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000478 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000479 int passes;
480 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
481
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000482 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000483 // fill rule, and set operation can
484 // we render the element directly to
485 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000486 canDrawDirectToClip =
487 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000488 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000489 clipBit,
bsalomon@google.comee435122011-07-01 14:57:55 +0000490 fillInverted,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000491 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000492
493 // draw the element to the client stencil bits if necessary
494 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000495 static const GrStencilSettings gDrawToStencil = {
496 kIncClamp_StencilOp, kIncClamp_StencilOp,
497 kIncClamp_StencilOp, kIncClamp_StencilOp,
498 kAlways_StencilFunc, kAlways_StencilFunc,
499 0xffffffff, 0xffffffff,
500 0x00000000, 0x00000000,
501 0xffffffff, 0xffffffff,
502 };
503 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000504 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000505 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000506 this->drawSimpleRect(clip.getRect(c), NULL, 0);
507 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000508 if (canRenderDirectToStencil) {
509 this->setStencil(gDrawToStencil);
bsalomon@google.comee435122011-07-01 14:57:55 +0000510 pr->drawPath(0);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000511 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000512 pr->drawPathToStencil();
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000513 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000514 }
515 }
516
517 // now we modify the clip bit by rendering either the clip
518 // element directly or a bounding rect of the entire clip.
519 this->enableState(kModifyStencilClip_StateBit);
520 for (int p = 0; p < passes; ++p) {
521 this->setStencil(stencilSettings[p]);
522 if (canDrawDirectToClip) {
523 if (kRect_ClipType == clip.getElementType(c)) {
524 SET_RANDOM_COLOR
525 this->drawSimpleRect(clip.getRect(c), NULL, 0);
526 } else {
527 SET_RANDOM_COLOR
bsalomon@google.comee435122011-07-01 14:57:55 +0000528 pr->drawPath(0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000529 }
530 } else {
531 SET_RANDOM_COLOR
thakis@chromium.org441d7da2011-06-07 04:03:17 +0000532 this->drawSimpleRect(bounds, NULL, 0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000533 }
534 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000535 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000536 fClip = clip;
537 // recusive draws would have disabled this.
538 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000539 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000540
reed@google.comac10a2d2010-12-22 21:39:39 +0000541 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000542 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000543
reed@google.comac10a2d2010-12-22 21:39:39 +0000544 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000545 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000546 return false;
547 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000548 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000549 return true;
550}
551
reed@google.com07f3ee12011-05-16 17:21:57 +0000552GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000553 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000554 if (NULL != fClientPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +0000555 fClientPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000556 return fClientPathRenderer;
557 } else {
558 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000559 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000560 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
561 this->supportsStencilWrapOps());
562 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000563 GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000564 return fDefaultPathRenderer;
565 }
566}
567
568
bsalomon@google.comd302f142011-03-03 13:54:13 +0000569////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000570
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000571void GrGpu::geometrySourceWillPush() {
572 const GeometrySrcState& geoSrc = this->getGeomSrc();
573 if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
574 kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
575 this->finalizeReservedVertices();
576 }
577 if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
578 kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
579 this->finalizeReservedIndices();
580 }
581 GeometryPoolState& newState = fGeomPoolStateStack.push_back();
582#if GR_DEBUG
583 newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
584 newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
585 newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
586 newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
587#endif
588}
589
590void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
591 // if popping last entry then pops are unbalanced with pushes
592 GrAssert(fGeomPoolStateStack.count() > 1);
593 fGeomPoolStateStack.pop_back();
594}
595
596void GrGpu::onDrawIndexed(GrPrimitiveType type,
597 int startVertex,
598 int startIndex,
599 int vertexCount,
600 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000601
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000602 this->handleDirtyContext();
603
604 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000605 return;
606 }
607
608#if GR_COLLECT_STATS
609 fStats.fVertexCnt += vertexCount;
610 fStats.fIndexCnt += indexCount;
611 fStats.fDrawCnt += 1;
612#endif
613
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000614 int sVertex = startVertex;
615 int sIndex = startIndex;
616 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000617
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000618 this->onGpuDrawIndexed(type, sVertex, sIndex,
619 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000620}
621
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000622void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000623 int startVertex,
624 int vertexCount) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000625 this->handleDirtyContext();
626
627 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000628 return;
629 }
630#if GR_COLLECT_STATS
631 fStats.fVertexCnt += vertexCount;
632 fStats.fDrawCnt += 1;
633#endif
634
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000635 int sVertex = startVertex;
636 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000637
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000638 this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000639}
640
641void GrGpu::finalizeReservedVertices() {
642 GrAssert(NULL != fVertexPool);
643 fVertexPool->unlock();
644}
645
646void GrGpu::finalizeReservedIndices() {
647 GrAssert(NULL != fIndexPool);
648 fIndexPool->unlock();
649}
650
651void GrGpu::prepareVertexPool() {
652 if (NULL == fVertexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000653 GrAssert(0 == fVertexPoolUseCnt);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000654 fVertexPool = new GrVertexBufferAllocPool(this, true,
655 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000656 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000657 fVertexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000658 } else if (!fVertexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000659 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000660 fVertexPool->reset();
661 }
662}
663
664void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000665 if (NULL == fIndexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000666 GrAssert(0 == fIndexPoolUseCnt);
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000667 fIndexPool = new GrIndexBufferAllocPool(this, true,
668 INDEX_POOL_IB_SIZE,
669 INDEX_POOL_IB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000670 fIndexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000671 } else if (!fIndexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000672 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000673 fIndexPool->reset();
674 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000675}
676
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000677bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
678 int vertexCount,
679 void** vertices) {
680 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
681
682 GrAssert(vertexCount > 0);
683 GrAssert(NULL != vertices);
684
685 this->prepareVertexPool();
686
687 *vertices = fVertexPool->makeSpace(vertexLayout,
688 vertexCount,
689 &geomPoolState.fPoolVertexBuffer,
690 &geomPoolState.fPoolStartVertex);
691 if (NULL == *vertices) {
692 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000693 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000694 ++fVertexPoolUseCnt;
reed@google.comac10a2d2010-12-22 21:39:39 +0000695 return true;
696}
697
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000698bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
699 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
700
701 GrAssert(indexCount > 0);
702 GrAssert(NULL != indices);
703
704 this->prepareIndexPool();
705
706 *indices = fIndexPool->makeSpace(indexCount,
707 &geomPoolState.fPoolIndexBuffer,
708 &geomPoolState.fPoolStartIndex);
709 if (NULL == *indices) {
710 return false;
711 }
712 ++fIndexPoolUseCnt;
713 return true;
714}
715
716void GrGpu::releaseReservedVertexSpace() {
717 const GeometrySrcState& geoSrc = this->getGeomSrc();
718 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
719 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
720 fVertexPool->putBack(bytes);
721 --fVertexPoolUseCnt;
722}
723
724void GrGpu::releaseReservedIndexSpace() {
725 const GeometrySrcState& geoSrc = this->getGeomSrc();
726 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
727 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
728 fIndexPool->putBack(bytes);
729 --fIndexPoolUseCnt;
730}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000731
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000732void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000733 this->prepareVertexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000734 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000735#if GR_DEBUG
736 bool success =
737#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000738 fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000739 vertexCount,
740 vertexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000741 &geomPoolState.fPoolVertexBuffer,
742 &geomPoolState.fPoolStartVertex);
743 ++fVertexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000744 GR_DEBUGASSERT(success);
745}
746
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000747void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000748 this->prepareIndexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000749 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000750#if GR_DEBUG
751 bool success =
752#endif
753 fIndexPool->appendIndices(indexCount,
754 indexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000755 &geomPoolState.fPoolIndexBuffer,
756 &geomPoolState.fPoolStartIndex);
757 ++fIndexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000758 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000759}
760
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000761void GrGpu::releaseVertexArray() {
762 // if vertex source was array, we stowed data in the pool
763 const GeometrySrcState& geoSrc = this->getGeomSrc();
764 GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
765 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
766 fVertexPool->putBack(bytes);
767 --fVertexPoolUseCnt;
768}
769
770void GrGpu::releaseIndexArray() {
771 // if index source was array, we stowed data in the pool
772 const GeometrySrcState& geoSrc = this->getGeomSrc();
773 GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
774 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
775 fIndexPool->putBack(bytes);
776 --fIndexPoolUseCnt;
777}
778
bsalomon@google.comd302f142011-03-03 13:54:13 +0000779////////////////////////////////////////////////////////////////////////////////
780
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000781const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000782 return fStats;
783}
784
785void GrGpu::resetStats() {
786 memset(&fStats, 0, sizeof(fStats));
787}
788
789void GrGpu::printStats() const {
790 if (GR_COLLECT_STATS) {
791 GrPrintf(
792 "-v-------------------------GPU STATS----------------------------v-\n"
793 "Stats collection is: %s\n"
794 "Draws: %04d, Verts: %04d, Indices: %04d\n"
795 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
796 "TexCreates: %04d, RTCreates:%04d\n"
797 "-^--------------------------------------------------------------^-\n",
798 (GR_COLLECT_STATS ? "ON" : "OFF"),
799 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
800 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
801 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
802 }
803}
804
805////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000806const GrSamplerState GrSamplerState::gClampNoFilter(
807 GrSamplerState::kClamp_WrapMode,
808 GrSamplerState::kClamp_WrapMode,
809 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000810 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000811 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000812
813
814
815