blob: 192d29b0d40e69ddefbc3db036cc11054be311f3 [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.com7a5af8b2011-02-18 18:40:42 +000027static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
28static const int VERTEX_POOL_VB_COUNT = 1;
reed@google.comac10a2d2010-12-22 21:39:39 +000029
reed@google.comac10a2d2010-12-22 21:39:39 +000030
bsalomon@google.comd302f142011-03-03 13:54:13 +000031////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000032
33extern void gr_run_unittests();
34
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000035#define DEBUG_INVAL_BUFFER 0xdeadcafe
36#define DEBUG_INVAL_START_IDX -1
37
bsalomon@google.com8fe72472011-03-30 21:26:44 +000038GrGpu::GrGpu()
39 : f8bitPaletteSupport(false)
bsalomon@google.com669fdc42011-04-05 17:08:27 +000040 , fContext(NULL)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000041 , fVertexPool(NULL)
42 , fIndexPool(NULL)
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000043 , fVertexPoolUseCnt(0)
44 , fIndexPoolUseCnt(0)
45 , fGeomPoolStateStack(&fGeoSrcStateStackStorage)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000046 , fQuadIndexBuffer(NULL)
47 , fUnitSquareVertexBuffer(NULL)
48 , fDefaultPathRenderer(NULL)
49 , fClientPathRenderer(NULL)
50 , fContextIsDirty(true)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000051 , fResourceHead(NULL) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +000052
reed@google.comac10a2d2010-12-22 21:39:39 +000053#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000054 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000055#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000056
57 fGeomPoolStateStack.push_back();
58#if GR_DEBUG
59 GeometryPoolState& poolState = fGeomPoolStateStack.back();
60 poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
61 poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
62 poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
63 poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
64#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000065 resetStats();
66}
67
68GrGpu::~GrGpu() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000069 releaseResources();
reed@google.comac10a2d2010-12-22 21:39:39 +000070}
71
bsalomon@google.com8fe72472011-03-30 21:26:44 +000072void GrGpu::abandonResources() {
73
74 while (NULL != fResourceHead) {
75 fResourceHead->abandon();
76 }
77
78 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
79 GrAssert(NULL == fUnitSquareVertexBuffer ||
80 !fUnitSquareVertexBuffer->isValid());
81 GrSafeSetNull(fQuadIndexBuffer);
82 GrSafeSetNull(fUnitSquareVertexBuffer);
83 delete fVertexPool;
84 fVertexPool = NULL;
85 delete fIndexPool;
86 fIndexPool = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000087}
88
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089void GrGpu::releaseResources() {
90
91 while (NULL != fResourceHead) {
92 fResourceHead->release();
93 }
94
95 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
96 GrAssert(NULL == fUnitSquareVertexBuffer ||
97 !fUnitSquareVertexBuffer->isValid());
98 GrSafeSetNull(fQuadIndexBuffer);
99 GrSafeSetNull(fUnitSquareVertexBuffer);
100 delete fVertexPool;
101 fVertexPool = NULL;
102 delete fIndexPool;
103 fIndexPool = NULL;
104}
105
106void GrGpu::insertResource(GrResource* resource) {
107 GrAssert(NULL != resource);
108 GrAssert(this == resource->getGpu());
109 GrAssert(NULL == resource->fNext);
110 GrAssert(NULL == resource->fPrevious);
111
112 resource->fNext = fResourceHead;
113 if (NULL != fResourceHead) {
114 GrAssert(NULL == fResourceHead->fPrevious);
115 fResourceHead->fPrevious = resource;
116 }
117 fResourceHead = resource;
118}
119
120void GrGpu::removeResource(GrResource* resource) {
121 GrAssert(NULL != resource);
122 GrAssert(NULL != fResourceHead);
123
124 if (fResourceHead == resource) {
125 GrAssert(NULL == resource->fPrevious);
126 fResourceHead = resource->fNext;
127 } else {
128 GrAssert(NULL != fResourceHead);
129 resource->fPrevious->fNext = resource->fNext;
130 }
131 if (NULL != resource->fNext) {
132 resource->fNext->fPrevious = resource->fPrevious;
133 }
134 resource->fNext = NULL;
135 resource->fPrevious = NULL;
136}
137
138
reed@google.comac10a2d2010-12-22 21:39:39 +0000139void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000140#if GR_DEBUG
141 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
142#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000143}
144
bsalomon@google.comd302f142011-03-03 13:54:13 +0000145////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000146
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000147GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000148 const void* srcData, size_t rowBytes) {
149 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000150 return this->onCreateTexture(desc, srcData, rowBytes);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000151}
152
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000153GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
154 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000155 return this->onCreateRenderTargetFrom3DApiState();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000156}
157
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000158GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
159 this->handleDirtyContext();
160 return this->onCreatePlatformSurface(desc);
161}
162
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000163GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
164 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000165 return this->onCreateVertexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000166}
167
168GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
169 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000170 return this->onCreateIndexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000171}
172
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000173void GrGpu::clear(const GrIRect* rect, GrColor color) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000174 this->handleDirtyContext();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000175 this->onClear(rect, color);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000176}
177
178void GrGpu::forceRenderTargetFlush() {
179 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000180 this->onForceRenderTargetFlush();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000181}
182
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000183bool GrGpu::readPixels(GrRenderTarget* target,
184 int left, int top, int width, int height,
185 GrPixelConfig config, void* buffer) {
186
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000187 this->handleDirtyContext();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000188 return this->onReadPixels(target, left, top, width, height, config, buffer);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000189}
190
191////////////////////////////////////////////////////////////////////////////////
192
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000193static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000194
reed@google.com8195f672011-01-12 18:14:28 +0000195GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000196
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000197static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000198 for (int i = 0; i < quadCount; ++i) {
199 indices[6 * i + 0] = 4 * i + 0;
200 indices[6 * i + 1] = 4 * i + 1;
201 indices[6 * i + 2] = 4 * i + 2;
202 indices[6 * i + 3] = 4 * i + 0;
203 indices[6 * i + 4] = 4 * i + 2;
204 indices[6 * i + 5] = 4 * i + 3;
205 }
206}
207
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000208const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000209 if (NULL == fQuadIndexBuffer) {
210 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
211 GrGpu* me = const_cast<GrGpu*>(this);
212 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
213 if (NULL != fQuadIndexBuffer) {
214 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
215 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000216 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000217 fQuadIndexBuffer->unlock();
218 } else {
219 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000220 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000221 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
222 fQuadIndexBuffer->unref();
223 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000224 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000225 }
226 GrFree(indices);
227 }
228 }
229 }
230
231 return fQuadIndexBuffer;
232}
233
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000234const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000235 if (NULL == fUnitSquareVertexBuffer) {
236
237 static const GrPoint DATA[] = {
reed@google.com7744c202011-05-06 19:26:26 +0000238 { 0, 0 },
239 { GR_Scalar1, 0 },
240 { GR_Scalar1, GR_Scalar1 },
241 { 0, GR_Scalar1 }
242#if 0
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000243 GrPoint(0, 0),
244 GrPoint(GR_Scalar1,0),
245 GrPoint(GR_Scalar1,GR_Scalar1),
246 GrPoint(0, GR_Scalar1)
reed@google.com7744c202011-05-06 19:26:26 +0000247#endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000248 };
249 static const size_t SIZE = sizeof(DATA);
250
251 GrGpu* me = const_cast<GrGpu*>(this);
252 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
253 if (NULL != fUnitSquareVertexBuffer) {
254 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
255 fUnitSquareVertexBuffer->unref();
256 fUnitSquareVertexBuffer = NULL;
257 GrCrash("Can't get vertices into buffer!");
258 }
259 }
260 }
261
262 return fUnitSquareVertexBuffer;
263}
264
bsalomon@google.comd302f142011-03-03 13:54:13 +0000265////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000266
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000267void GrGpu::clipWillBeSet(const GrClip& newClip) {
268 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000269 fClipState.fClipIsDirty = true;
270 }
271}
272
bsalomon@google.comd302f142011-03-03 13:54:13 +0000273////////////////////////////////////////////////////////////////////////////////
274
275// stencil settings to use when clip is in stencil
276const GrStencilSettings GrGpu::gClipStencilSettings = {
277 kKeep_StencilOp, kKeep_StencilOp,
278 kKeep_StencilOp, kKeep_StencilOp,
279 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
280 0, 0,
281 0, 0,
282 0, 0
283};
284
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000285// mapping of clip-respecting stencil funcs to normal stencil funcs
286// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000287static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
288 {// Stencil-Clipping is DISABLED, effectively always inside the clip
289 // In the Clip Funcs
290 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
291 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
292 kLess_StencilFunc, // kLessIfInClip_StencilFunc
293 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
294 // Special in the clip func that forces user's ref to be 0.
295 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
296 // make ref 0 and do normal nequal.
297 },
298 {// Stencil-Clipping is ENABLED
299 // In the Clip Funcs
300 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
301 // eq stencil clip bit, mask
302 // out user bits.
303
304 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
305 // add stencil bit to mask and ref
306
307 kLess_StencilFunc, // kLessIfInClip_StencilFunc
308 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
309 // for both of these we can add
310 // the clip bit to the mask and
311 // ref and compare as normal
312 // Special in the clip func that forces user's ref to be 0.
313 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
314 // make ref have only the clip bit set
315 // and make comparison be less
316 // 10..0 < 1..user_bits..
317 }
318};
319
320GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
321 GrAssert(func >= 0);
322 if (func >= kBasicStencilFuncCount) {
323 GrAssert(func < kStencilFuncCount);
324 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
325 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
326 }
327 return func;
328}
329
330void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
331 bool clipInStencil,
332 unsigned int clipBit,
333 unsigned int userBits,
334 unsigned int* ref,
335 unsigned int* mask) {
336 if (func < kBasicStencilFuncCount) {
337 *mask &= userBits;
338 *ref &= userBits;
339 } else {
340 if (clipInStencil) {
341 switch (func) {
342 case kAlwaysIfInClip_StencilFunc:
343 *mask = clipBit;
344 *ref = clipBit;
345 break;
346 case kEqualIfInClip_StencilFunc:
347 case kLessIfInClip_StencilFunc:
348 case kLEqualIfInClip_StencilFunc:
349 *mask = (*mask & userBits) | clipBit;
350 *ref = (*ref & userBits) | clipBit;
351 break;
352 case kNonZeroIfInClip_StencilFunc:
353 *mask = (*mask & userBits) | clipBit;
354 *ref = clipBit;
355 break;
356 default:
357 GrCrash("Unknown stencil func");
358 }
359 } else {
360 *mask &= userBits;
361 *ref &= userBits;
362 }
363 }
364}
365
366////////////////////////////////////////////////////////////////////////////////
367
368#define VISUALIZE_COMPLEX_CLIP 0
369
370#if VISUALIZE_COMPLEX_CLIP
371 #include "GrRandom.h"
372 GrRandom gRandom;
373 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
374#else
375 #define SET_RANDOM_COLOR
376#endif
377
bsalomon@google.comffca4002011-02-22 20:34:01 +0000378bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000379 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000380 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000381
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000382 // we check this early because we need a valid
383 // render target to setup stencil clipping
384 // before even going into flushGraphicsState
385 if (NULL == fCurrDrawState.fRenderTarget) {
386 GrAssert(!"No render target bound.");
387 return false;
388 }
389
reed@google.comac10a2d2010-12-22 21:39:39 +0000390 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000391 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
392
393 GrRect bounds;
394 GrRect rtRect;
395 rtRect.setLTRB(0, 0,
396 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000397 if (fClip.hasConservativeBounds()) {
398 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000399 if (!bounds.intersect(rtRect)) {
400 bounds.setEmpty();
401 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000402 } else {
403 bounds = rtRect;
404 }
405
406 bounds.roundOut(&clipRect);
407 if (clipRect.isEmpty()) {
408 clipRect.setLTRB(0,0,0,0);
409 }
410 r = &clipRect;
411
412 fClipState.fClipInStencil = !fClip.isRect() &&
413 !fClip.isEmpty() &&
414 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000415
416 if (fClipState.fClipInStencil &&
417 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000418 fClip != rt.fLastStencilClip)) {
419
420 rt.fLastStencilClip = fClip;
421 // we set the current clip to the bounds so that our recursive
422 // draws are scissored to them. We use the copy of the complex clip
423 // in the rt to render
424 const GrClip& clip = rt.fLastStencilClip;
425 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000426
427 AutoStateRestore asr(this);
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000428 AutoGeometryPush agp(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000429
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000430 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000431 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000432 this->flushScissor(NULL);
433#if !VISUALIZE_COMPLEX_CLIP
434 this->enableState(kNoColorWrites_StateBit);
435#else
436 this->disableState(kNoColorWrites_StateBit);
437#endif
438 int count = clip.getElementCount();
439 int clipBit = rt.stencilBits();
440 clipBit = (1 << (clipBit-1));
441
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000442 // often we'll see the first two elements of the clip are
443 // the full rt size and another element intersected with it.
444 // We can skip the first full-size rect and save a big rect draw.
445 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000446 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000447 kRect_ClipType == clip.getElementType(0) &&
448 kIntersect_SetOp == clip.getOp(1)&&
449 clip.getRect(0).contains(bounds)) {
450 firstElement = 1;
451 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000452
bsalomon@google.comd302f142011-03-03 13:54:13 +0000453 // walk through each clip element and perform its set op
454 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000455 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000456 GrPathFill fill;
457 // 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.comd302f142011-03-03 13:54:13 +0000468 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000469 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000470 fill = kEvenOdd_PathFill;
471 } else {
472 fill = clip.getPathFill(c);
reed@google.com07f3ee12011-05-16 17:21:57 +0000473 clipPath = &clip.getPath(c);
474 pr = this->getClipPathRenderer(*clipPath, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000475 canRenderDirectToStencil =
reed@google.com07f3ee12011-05-16 17:21:57 +0000476 !pr->requiresStencilPass(this, *clipPath,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000477 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000478 }
479
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000480 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000481 int passes;
482 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
483
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000484 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000485 // fill rule, and set operation can
486 // we render the element directly to
487 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000488 canDrawDirectToClip =
489 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000490 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000491 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000492 IsFillInverted(fill),
493 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000494
495 // draw the element to the client stencil bits if necessary
496 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000497 static const GrStencilSettings gDrawToStencil = {
498 kIncClamp_StencilOp, kIncClamp_StencilOp,
499 kIncClamp_StencilOp, kIncClamp_StencilOp,
500 kAlways_StencilFunc, kAlways_StencilFunc,
501 0xffffffff, 0xffffffff,
502 0x00000000, 0x00000000,
503 0xffffffff, 0xffffffff,
504 };
505 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000506 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000507 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000508 this->drawSimpleRect(clip.getRect(c), NULL, 0);
509 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000510 if (canRenderDirectToStencil) {
511 this->setStencil(gDrawToStencil);
reed@google.com07f3ee12011-05-16 17:21:57 +0000512 pr->drawPath(this, 0, *clipPath, NonInvertedFill(fill),
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000513 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000514 } else {
reed@google.com07f3ee12011-05-16 17:21:57 +0000515 pr->drawPathToStencil(this, *clipPath,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000516 NonInvertedFill(fill),
517 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000518 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000519 }
520 }
521
522 // now we modify the clip bit by rendering either the clip
523 // element directly or a bounding rect of the entire clip.
524 this->enableState(kModifyStencilClip_StateBit);
525 for (int p = 0; p < passes; ++p) {
526 this->setStencil(stencilSettings[p]);
527 if (canDrawDirectToClip) {
528 if (kRect_ClipType == clip.getElementType(c)) {
529 SET_RANDOM_COLOR
530 this->drawSimpleRect(clip.getRect(c), NULL, 0);
531 } else {
532 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000533 GrAssert(!IsFillInverted(fill));
reed@google.com07f3ee12011-05-16 17:21:57 +0000534 pr->drawPath(this, 0, *clipPath, fill, NULL);
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.comdfe75bc2011-03-25 12:31:16 +0000561 fClientPathRenderer->canDrawPath(this, path, fill)) {
562 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 }
569 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
570 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