blob: e18c4a4473848b3455abbb6ceaaaa434bde37894 [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"
18#include "GrMemory.h"
19#include "GrTextStrike.h"
20#include "GrTextureCache.h"
21#include "GrClipIterator.h"
22#include "GrIndexBuffer.h"
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000023#include "GrVertexBuffer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000024#include "GrBufferAllocPool.h"
bsalomon@google.comd302f142011-03-03 13:54:13 +000025#include "GrPathRenderer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000026
27// probably makes no sense for this to be less than a page
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +000028static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
29static const int VERTEX_POOL_VB_COUNT = 1;
reed@google.comac10a2d2010-12-22 21:39:39 +000030
reed@google.comac10a2d2010-12-22 21:39:39 +000031
bsalomon@google.comd302f142011-03-03 13:54:13 +000032////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000033
34extern void gr_run_unittests();
35
bsalomon@google.com8fe72472011-03-30 21:26:44 +000036GrGpu::GrGpu()
37 : f8bitPaletteSupport(false)
38 , fCurrPoolVertexBuffer(NULL)
39 , fCurrPoolStartVertex(0)
40 , fCurrPoolIndexBuffer(NULL)
41 , fCurrPoolStartIndex(0)
bsalomon@google.com669fdc42011-04-05 17:08:27 +000042 , fContext(NULL)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000043 , fVertexPool(NULL)
44 , fIndexPool(NULL)
45 , fQuadIndexBuffer(NULL)
46 , fUnitSquareVertexBuffer(NULL)
47 , fDefaultPathRenderer(NULL)
48 , fClientPathRenderer(NULL)
49 , fContextIsDirty(true)
50 , fVertexPoolInUse(false)
51 , fIndexPoolInUse(false)
52 , fResourceHead(NULL) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +000053
reed@google.comac10a2d2010-12-22 21:39:39 +000054#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000055 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000056#endif
57 resetStats();
58}
59
60GrGpu::~GrGpu() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000061 releaseResources();
reed@google.comac10a2d2010-12-22 21:39:39 +000062}
63
bsalomon@google.com8fe72472011-03-30 21:26:44 +000064void GrGpu::abandonResources() {
65
66 while (NULL != fResourceHead) {
67 fResourceHead->abandon();
68 }
69
70 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
71 GrAssert(NULL == fUnitSquareVertexBuffer ||
72 !fUnitSquareVertexBuffer->isValid());
73 GrSafeSetNull(fQuadIndexBuffer);
74 GrSafeSetNull(fUnitSquareVertexBuffer);
75 delete fVertexPool;
76 fVertexPool = NULL;
77 delete fIndexPool;
78 fIndexPool = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000079}
80
bsalomon@google.com8fe72472011-03-30 21:26:44 +000081void GrGpu::releaseResources() {
82
83 while (NULL != fResourceHead) {
84 fResourceHead->release();
85 }
86
87 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
88 GrAssert(NULL == fUnitSquareVertexBuffer ||
89 !fUnitSquareVertexBuffer->isValid());
90 GrSafeSetNull(fQuadIndexBuffer);
91 GrSafeSetNull(fUnitSquareVertexBuffer);
92 delete fVertexPool;
93 fVertexPool = NULL;
94 delete fIndexPool;
95 fIndexPool = NULL;
96}
97
98void GrGpu::insertResource(GrResource* resource) {
99 GrAssert(NULL != resource);
100 GrAssert(this == resource->getGpu());
101 GrAssert(NULL == resource->fNext);
102 GrAssert(NULL == resource->fPrevious);
103
104 resource->fNext = fResourceHead;
105 if (NULL != fResourceHead) {
106 GrAssert(NULL == fResourceHead->fPrevious);
107 fResourceHead->fPrevious = resource;
108 }
109 fResourceHead = resource;
110}
111
112void GrGpu::removeResource(GrResource* resource) {
113 GrAssert(NULL != resource);
114 GrAssert(NULL != fResourceHead);
115
116 if (fResourceHead == resource) {
117 GrAssert(NULL == resource->fPrevious);
118 fResourceHead = resource->fNext;
119 } else {
120 GrAssert(NULL != fResourceHead);
121 resource->fPrevious->fNext = resource->fNext;
122 }
123 if (NULL != resource->fNext) {
124 resource->fNext->fPrevious = resource->fPrevious;
125 }
126 resource->fNext = NULL;
127 resource->fPrevious = NULL;
128}
129
130
reed@google.comac10a2d2010-12-22 21:39:39 +0000131void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000132#if GR_DEBUG
133 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
134#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000135}
136
bsalomon@google.comd302f142011-03-03 13:54:13 +0000137////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000138
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000139GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000140 const void* srcData, size_t rowBytes) {
141 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000142 return this->onCreateTexture(desc, srcData, rowBytes);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000143}
144
145GrRenderTarget* GrGpu::createPlatformRenderTarget(intptr_t platformRenderTarget,
146 int stencilBits,
bsalomon@google.comf954d8d2011-04-06 17:50:02 +0000147 bool isMultisampled,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000148 int width, int height) {
149 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000150 return this->onCreatePlatformRenderTarget(platformRenderTarget,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000151 stencilBits,
bsalomon@google.comf954d8d2011-04-06 17:50:02 +0000152 isMultisampled,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000153 width, height);
154}
155
156GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
157 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000158 return this->onCreateRenderTargetFrom3DApiState();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000159}
160
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000161GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
162 this->handleDirtyContext();
163 return this->onCreatePlatformSurface(desc);
164}
165
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000166GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
167 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000168 return this->onCreateVertexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000169}
170
171GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
172 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000173 return this->onCreateIndexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000174}
175
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000176void GrGpu::clear(const GrIRect* rect, GrColor color) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000177 this->handleDirtyContext();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000178 this->onClear(rect, color);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000179}
180
181void GrGpu::forceRenderTargetFlush() {
182 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000183 this->onForceRenderTargetFlush();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000184}
185
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000186bool GrGpu::readPixels(GrRenderTarget* target,
187 int left, int top, int width, int height,
188 GrPixelConfig config, void* buffer) {
189
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000190 this->handleDirtyContext();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000191 return this->onReadPixels(target, left, top, width, height, config, buffer);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000192}
193
194////////////////////////////////////////////////////////////////////////////////
195
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000196static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000197
reed@google.com8195f672011-01-12 18:14:28 +0000198GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000199
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000200static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000201 for (int i = 0; i < quadCount; ++i) {
202 indices[6 * i + 0] = 4 * i + 0;
203 indices[6 * i + 1] = 4 * i + 1;
204 indices[6 * i + 2] = 4 * i + 2;
205 indices[6 * i + 3] = 4 * i + 0;
206 indices[6 * i + 4] = 4 * i + 2;
207 indices[6 * i + 5] = 4 * i + 3;
208 }
209}
210
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000211const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000212 if (NULL == fQuadIndexBuffer) {
213 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
214 GrGpu* me = const_cast<GrGpu*>(this);
215 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
216 if (NULL != fQuadIndexBuffer) {
217 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
218 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000219 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000220 fQuadIndexBuffer->unlock();
221 } else {
222 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000223 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000224 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
225 fQuadIndexBuffer->unref();
226 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000227 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000228 }
229 GrFree(indices);
230 }
231 }
232 }
233
234 return fQuadIndexBuffer;
235}
236
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000237const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000238 if (NULL == fUnitSquareVertexBuffer) {
239
240 static const GrPoint DATA[] = {
241 GrPoint(0, 0),
242 GrPoint(GR_Scalar1,0),
243 GrPoint(GR_Scalar1,GR_Scalar1),
244 GrPoint(0, GR_Scalar1)
245 };
246 static const size_t SIZE = sizeof(DATA);
247
248 GrGpu* me = const_cast<GrGpu*>(this);
249 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
250 if (NULL != fUnitSquareVertexBuffer) {
251 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
252 fUnitSquareVertexBuffer->unref();
253 fUnitSquareVertexBuffer = NULL;
254 GrCrash("Can't get vertices into buffer!");
255 }
256 }
257 }
258
259 return fUnitSquareVertexBuffer;
260}
261
bsalomon@google.comd302f142011-03-03 13:54:13 +0000262////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000263
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000264void GrGpu::clipWillBeSet(const GrClip& newClip) {
265 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000266 fClipState.fClipIsDirty = true;
267 }
268}
269
bsalomon@google.comd302f142011-03-03 13:54:13 +0000270////////////////////////////////////////////////////////////////////////////////
271
272// stencil settings to use when clip is in stencil
273const GrStencilSettings GrGpu::gClipStencilSettings = {
274 kKeep_StencilOp, kKeep_StencilOp,
275 kKeep_StencilOp, kKeep_StencilOp,
276 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
277 0, 0,
278 0, 0,
279 0, 0
280};
281
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000282// mapping of clip-respecting stencil funcs to normal stencil funcs
283// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000284static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
285 {// Stencil-Clipping is DISABLED, effectively always inside the clip
286 // In the Clip Funcs
287 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
288 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
289 kLess_StencilFunc, // kLessIfInClip_StencilFunc
290 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
291 // Special in the clip func that forces user's ref to be 0.
292 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
293 // make ref 0 and do normal nequal.
294 },
295 {// Stencil-Clipping is ENABLED
296 // In the Clip Funcs
297 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
298 // eq stencil clip bit, mask
299 // out user bits.
300
301 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
302 // add stencil bit to mask and ref
303
304 kLess_StencilFunc, // kLessIfInClip_StencilFunc
305 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
306 // for both of these we can add
307 // the clip bit to the mask and
308 // ref and compare as normal
309 // Special in the clip func that forces user's ref to be 0.
310 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
311 // make ref have only the clip bit set
312 // and make comparison be less
313 // 10..0 < 1..user_bits..
314 }
315};
316
317GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
318 GrAssert(func >= 0);
319 if (func >= kBasicStencilFuncCount) {
320 GrAssert(func < kStencilFuncCount);
321 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
322 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
323 }
324 return func;
325}
326
327void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
328 bool clipInStencil,
329 unsigned int clipBit,
330 unsigned int userBits,
331 unsigned int* ref,
332 unsigned int* mask) {
333 if (func < kBasicStencilFuncCount) {
334 *mask &= userBits;
335 *ref &= userBits;
336 } else {
337 if (clipInStencil) {
338 switch (func) {
339 case kAlwaysIfInClip_StencilFunc:
340 *mask = clipBit;
341 *ref = clipBit;
342 break;
343 case kEqualIfInClip_StencilFunc:
344 case kLessIfInClip_StencilFunc:
345 case kLEqualIfInClip_StencilFunc:
346 *mask = (*mask & userBits) | clipBit;
347 *ref = (*ref & userBits) | clipBit;
348 break;
349 case kNonZeroIfInClip_StencilFunc:
350 *mask = (*mask & userBits) | clipBit;
351 *ref = clipBit;
352 break;
353 default:
354 GrCrash("Unknown stencil func");
355 }
356 } else {
357 *mask &= userBits;
358 *ref &= userBits;
359 }
360 }
361}
362
363////////////////////////////////////////////////////////////////////////////////
364
365#define VISUALIZE_COMPLEX_CLIP 0
366
367#if VISUALIZE_COMPLEX_CLIP
368 #include "GrRandom.h"
369 GrRandom gRandom;
370 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
371#else
372 #define SET_RANDOM_COLOR
373#endif
374
bsalomon@google.comffca4002011-02-22 20:34:01 +0000375bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000376 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000377 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000378
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000379 // we check this early because we need a valid
380 // render target to setup stencil clipping
381 // before even going into flushGraphicsState
382 if (NULL == fCurrDrawState.fRenderTarget) {
383 GrAssert(!"No render target bound.");
384 return false;
385 }
386
reed@google.comac10a2d2010-12-22 21:39:39 +0000387 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000388 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
389
390 GrRect bounds;
391 GrRect rtRect;
392 rtRect.setLTRB(0, 0,
393 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000394 if (fClip.hasConservativeBounds()) {
395 bounds = fClip.getConservativeBounds();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000396 bounds.intersectWith(rtRect);
397 } else {
398 bounds = rtRect;
399 }
400
401 bounds.roundOut(&clipRect);
402 if (clipRect.isEmpty()) {
403 clipRect.setLTRB(0,0,0,0);
404 }
405 r = &clipRect;
406
407 fClipState.fClipInStencil = !fClip.isRect() &&
408 !fClip.isEmpty() &&
409 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000410
411 if (fClipState.fClipInStencil &&
412 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000413 fClip != rt.fLastStencilClip)) {
414
415 rt.fLastStencilClip = fClip;
416 // we set the current clip to the bounds so that our recursive
417 // draws are scissored to them. We use the copy of the complex clip
418 // in the rt to render
419 const GrClip& clip = rt.fLastStencilClip;
420 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000421
422 AutoStateRestore asr(this);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000423 AutoInternalDrawGeomRestore aidgr(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000424
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000425 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000426 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000427 this->flushScissor(NULL);
428#if !VISUALIZE_COMPLEX_CLIP
429 this->enableState(kNoColorWrites_StateBit);
430#else
431 this->disableState(kNoColorWrites_StateBit);
432#endif
433 int count = clip.getElementCount();
434 int clipBit = rt.stencilBits();
435 clipBit = (1 << (clipBit-1));
436
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000437 // often we'll see the first two elements of the clip are
438 // the full rt size and another element intersected with it.
439 // We can skip the first full-size rect and save a big rect draw.
440 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000441 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000442 kRect_ClipType == clip.getElementType(0) &&
443 kIntersect_SetOp == clip.getOp(1)&&
444 clip.getRect(0).contains(bounds)) {
445 firstElement = 1;
446 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000447
bsalomon@google.comd302f142011-03-03 13:54:13 +0000448 // walk through each clip element and perform its set op
449 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000450 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000451 GrPathFill fill;
452 // enabled at bottom of loop
453 this->disableState(kModifyStencilClip_StateBit);
454
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000455 bool canRenderDirectToStencil; // can the clip element be drawn
456 // directly to the stencil buffer
457 // with a non-inverted fill rule
458 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000459 // resolve in/out status.
460
461 GrPathRenderer* pr = NULL;
462 GrPath::Iter pathIter;
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;
466 } else {
467 fill = clip.getPathFill(c);
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000468 const GrPath& path = clip.getPath(c);
469 pathIter.reset(path);
470 pr = this->getClipPathRenderer(&pathIter, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000471 canRenderDirectToStencil =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000472 !pr->requiresStencilPass(this, &pathIter,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000473 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000474 }
475
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000476 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000477 int passes;
478 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
479
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000480 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000481 // fill rule, and set operation can
482 // we render the element directly to
483 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000484 canDrawDirectToClip =
485 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000486 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000487 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000488 IsFillInverted(fill),
489 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000490
491 // draw the element to the client stencil bits if necessary
492 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000493 static const GrStencilSettings gDrawToStencil = {
494 kIncClamp_StencilOp, kIncClamp_StencilOp,
495 kIncClamp_StencilOp, kIncClamp_StencilOp,
496 kAlways_StencilFunc, kAlways_StencilFunc,
497 0xffffffff, 0xffffffff,
498 0x00000000, 0x00000000,
499 0xffffffff, 0xffffffff,
500 };
501 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000502 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000503 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000504 this->drawSimpleRect(clip.getRect(c), NULL, 0);
505 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000506 if (canRenderDirectToStencil) {
507 this->setStencil(gDrawToStencil);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000508 pr->drawPath(this, 0,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000509 &pathIter,
510 NonInvertedFill(fill),
511 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000512 } else {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000513 pr->drawPathToStencil(this, &pathIter,
514 NonInvertedFill(fill),
515 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000516 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000517 }
518 }
519
520 // now we modify the clip bit by rendering either the clip
521 // element directly or a bounding rect of the entire clip.
522 this->enableState(kModifyStencilClip_StateBit);
523 for (int p = 0; p < passes; ++p) {
524 this->setStencil(stencilSettings[p]);
525 if (canDrawDirectToClip) {
526 if (kRect_ClipType == clip.getElementType(c)) {
527 SET_RANDOM_COLOR
528 this->drawSimpleRect(clip.getRect(c), NULL, 0);
529 } else {
530 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000531 GrAssert(!IsFillInverted(fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000532 pr->drawPath(this, 0, &pathIter, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000533 }
534 } else {
535 SET_RANDOM_COLOR
536 this->drawSimpleRect(bounds, 0, NULL);
537 }
538 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000539 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000540 fClip = clip;
541 // recusive draws would have disabled this.
542 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000543 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000544
reed@google.comac10a2d2010-12-22 21:39:39 +0000545 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000546 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000547
reed@google.comac10a2d2010-12-22 21:39:39 +0000548 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000549 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000550 return false;
551 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000552 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000553 return true;
554}
555
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000556GrPathRenderer* GrGpu::getClipPathRenderer(GrPathIter* path,
557 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000558 if (NULL != fClientPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000559 fClientPathRenderer->canDrawPath(this, path, fill)) {
560 return fClientPathRenderer;
561 } else {
562 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000563 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000564 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
565 this->supportsStencilWrapOps());
566 }
567 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
568 return fDefaultPathRenderer;
569 }
570}
571
572
bsalomon@google.comd302f142011-03-03 13:54:13 +0000573////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000574
bsalomon@google.comffca4002011-02-22 20:34:01 +0000575void GrGpu::drawIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000576 int startVertex,
577 int startIndex,
578 int vertexCount,
579 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000580 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
581 fReservedGeometry.fLocked);
582 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
583 fReservedGeometry.fLocked);
584
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000585 this->handleDirtyContext();
586
587 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000588 return;
589 }
590
591#if GR_COLLECT_STATS
592 fStats.fVertexCnt += vertexCount;
593 fStats.fIndexCnt += indexCount;
594 fStats.fDrawCnt += 1;
595#endif
596
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000597 int sVertex = startVertex;
598 int sIndex = startIndex;
599 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000600
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000601 this->onDrawIndexed(type, sVertex, sIndex,
602 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000603}
604
bsalomon@google.comffca4002011-02-22 20:34:01 +0000605void GrGpu::drawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000606 int startVertex,
607 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000608 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
609 fReservedGeometry.fLocked);
610
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000611 this->handleDirtyContext();
612
613 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000614 return;
615 }
616#if GR_COLLECT_STATS
617 fStats.fVertexCnt += vertexCount;
618 fStats.fDrawCnt += 1;
619#endif
620
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000621 int sVertex = startVertex;
622 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000623
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000624 this->onDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000625}
626
627void GrGpu::finalizeReservedVertices() {
628 GrAssert(NULL != fVertexPool);
629 fVertexPool->unlock();
630}
631
632void GrGpu::finalizeReservedIndices() {
633 GrAssert(NULL != fIndexPool);
634 fIndexPool->unlock();
635}
636
637void GrGpu::prepareVertexPool() {
638 if (NULL == fVertexPool) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000639 fVertexPool = new GrVertexBufferAllocPool(this, true,
640 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000641 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000642 fVertexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000643 } else if (!fVertexPoolInUse) {
644 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000645 fVertexPool->reset();
646 }
647}
648
649void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000650 if (NULL == fIndexPool) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000651 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000652 fIndexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000653 } else if (!fIndexPoolInUse) {
654 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000655 fIndexPool->reset();
656 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000657}
658
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000659bool GrGpu::onAcquireGeometry(GrVertexLayout vertexLayout,
660 void** vertices,
661 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000662 GrAssert(!fReservedGeometry.fLocked);
663 size_t reservedVertexSpace = 0;
664
665 if (fReservedGeometry.fVertexCount) {
666 GrAssert(NULL != vertices);
667
bsalomon@google.comd302f142011-03-03 13:54:13 +0000668 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000669
670 *vertices = fVertexPool->makeSpace(vertexLayout,
671 fReservedGeometry.fVertexCount,
672 &fCurrPoolVertexBuffer,
673 &fCurrPoolStartVertex);
674 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000675 return false;
676 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000677 reservedVertexSpace = VertexSize(vertexLayout) *
678 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000679 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000680 if (fReservedGeometry.fIndexCount) {
681 GrAssert(NULL != indices);
682
bsalomon@google.comd302f142011-03-03 13:54:13 +0000683 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000684
685 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
686 &fCurrPoolIndexBuffer,
687 &fCurrPoolStartIndex);
688 if (NULL == *indices) {
689 fVertexPool->putBack(reservedVertexSpace);
690 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000691 return false;
692 }
693 }
694 return true;
695}
696
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000697void GrGpu::onReleaseGeometry() {}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000698
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000699void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000700 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000701 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000702#if GR_DEBUG
703 bool success =
704#endif
705 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
706 vertexCount,
707 vertexArray,
708 &fCurrPoolVertexBuffer,
709 &fCurrPoolStartVertex);
710 GR_DEBUGASSERT(success);
711}
712
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000713void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000714 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000715 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000716#if GR_DEBUG
717 bool success =
718#endif
719 fIndexPool->appendIndices(indexCount,
720 indexArray,
721 &fCurrPoolIndexBuffer,
722 &fCurrPoolStartIndex);
723 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000724}
725
bsalomon@google.comd302f142011-03-03 13:54:13 +0000726////////////////////////////////////////////////////////////////////////////////
727
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000728const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000729 return fStats;
730}
731
732void GrGpu::resetStats() {
733 memset(&fStats, 0, sizeof(fStats));
734}
735
736void GrGpu::printStats() const {
737 if (GR_COLLECT_STATS) {
738 GrPrintf(
739 "-v-------------------------GPU STATS----------------------------v-\n"
740 "Stats collection is: %s\n"
741 "Draws: %04d, Verts: %04d, Indices: %04d\n"
742 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
743 "TexCreates: %04d, RTCreates:%04d\n"
744 "-^--------------------------------------------------------------^-\n",
745 (GR_COLLECT_STATS ? "ON" : "OFF"),
746 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
747 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
748 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
749 }
750}
751
752////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000753const GrSamplerState GrSamplerState::gClampNoFilter(
754 GrSamplerState::kClamp_WrapMode,
755 GrSamplerState::kClamp_WrapMode,
756 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000757 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000758 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000759
760
761
762