blob: 4f260c796727362b103ac61bd3526dde71f3994b [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
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000145GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
146 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000147 return this->onCreateRenderTargetFrom3DApiState();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000148}
149
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000150GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
151 this->handleDirtyContext();
152 return this->onCreatePlatformSurface(desc);
153}
154
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000155GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
156 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000157 return this->onCreateVertexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000158}
159
160GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
161 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000162 return this->onCreateIndexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000163}
164
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000165void GrGpu::clear(const GrIRect* rect, GrColor color) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000166 this->handleDirtyContext();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000167 this->onClear(rect, color);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000168}
169
170void GrGpu::forceRenderTargetFlush() {
171 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000172 this->onForceRenderTargetFlush();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000173}
174
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000175bool GrGpu::readPixels(GrRenderTarget* target,
176 int left, int top, int width, int height,
177 GrPixelConfig config, void* buffer) {
178
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000179 this->handleDirtyContext();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000180 return this->onReadPixels(target, left, top, width, height, config, buffer);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000181}
182
183////////////////////////////////////////////////////////////////////////////////
184
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000185static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000186
reed@google.com8195f672011-01-12 18:14:28 +0000187GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000188
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000189static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000190 for (int i = 0; i < quadCount; ++i) {
191 indices[6 * i + 0] = 4 * i + 0;
192 indices[6 * i + 1] = 4 * i + 1;
193 indices[6 * i + 2] = 4 * i + 2;
194 indices[6 * i + 3] = 4 * i + 0;
195 indices[6 * i + 4] = 4 * i + 2;
196 indices[6 * i + 5] = 4 * i + 3;
197 }
198}
199
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000200const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000201 if (NULL == fQuadIndexBuffer) {
202 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
203 GrGpu* me = const_cast<GrGpu*>(this);
204 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
205 if (NULL != fQuadIndexBuffer) {
206 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
207 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000208 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000209 fQuadIndexBuffer->unlock();
210 } else {
211 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000212 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000213 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
214 fQuadIndexBuffer->unref();
215 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000216 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000217 }
218 GrFree(indices);
219 }
220 }
221 }
222
223 return fQuadIndexBuffer;
224}
225
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000226const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000227 if (NULL == fUnitSquareVertexBuffer) {
228
229 static const GrPoint DATA[] = {
reed@google.com7744c202011-05-06 19:26:26 +0000230 { 0, 0 },
231 { GR_Scalar1, 0 },
232 { GR_Scalar1, GR_Scalar1 },
233 { 0, GR_Scalar1 }
234#if 0
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000235 GrPoint(0, 0),
236 GrPoint(GR_Scalar1,0),
237 GrPoint(GR_Scalar1,GR_Scalar1),
238 GrPoint(0, GR_Scalar1)
reed@google.com7744c202011-05-06 19:26:26 +0000239#endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000240 };
241 static const size_t SIZE = sizeof(DATA);
242
243 GrGpu* me = const_cast<GrGpu*>(this);
244 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
245 if (NULL != fUnitSquareVertexBuffer) {
246 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
247 fUnitSquareVertexBuffer->unref();
248 fUnitSquareVertexBuffer = NULL;
249 GrCrash("Can't get vertices into buffer!");
250 }
251 }
252 }
253
254 return fUnitSquareVertexBuffer;
255}
256
bsalomon@google.comd302f142011-03-03 13:54:13 +0000257////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000258
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000259void GrGpu::clipWillBeSet(const GrClip& newClip) {
260 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000261 fClipState.fClipIsDirty = true;
262 }
263}
264
bsalomon@google.comd302f142011-03-03 13:54:13 +0000265////////////////////////////////////////////////////////////////////////////////
266
267// stencil settings to use when clip is in stencil
268const GrStencilSettings GrGpu::gClipStencilSettings = {
269 kKeep_StencilOp, kKeep_StencilOp,
270 kKeep_StencilOp, kKeep_StencilOp,
271 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
272 0, 0,
273 0, 0,
274 0, 0
275};
276
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000277// mapping of clip-respecting stencil funcs to normal stencil funcs
278// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000279static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
280 {// Stencil-Clipping is DISABLED, effectively always inside the clip
281 // In the Clip Funcs
282 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
283 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
284 kLess_StencilFunc, // kLessIfInClip_StencilFunc
285 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
286 // Special in the clip func that forces user's ref to be 0.
287 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
288 // make ref 0 and do normal nequal.
289 },
290 {// Stencil-Clipping is ENABLED
291 // In the Clip Funcs
292 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
293 // eq stencil clip bit, mask
294 // out user bits.
295
296 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
297 // add stencil bit to mask and ref
298
299 kLess_StencilFunc, // kLessIfInClip_StencilFunc
300 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
301 // for both of these we can add
302 // the clip bit to the mask and
303 // ref and compare as normal
304 // Special in the clip func that forces user's ref to be 0.
305 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
306 // make ref have only the clip bit set
307 // and make comparison be less
308 // 10..0 < 1..user_bits..
309 }
310};
311
312GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
313 GrAssert(func >= 0);
314 if (func >= kBasicStencilFuncCount) {
315 GrAssert(func < kStencilFuncCount);
316 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
317 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
318 }
319 return func;
320}
321
322void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
323 bool clipInStencil,
324 unsigned int clipBit,
325 unsigned int userBits,
326 unsigned int* ref,
327 unsigned int* mask) {
328 if (func < kBasicStencilFuncCount) {
329 *mask &= userBits;
330 *ref &= userBits;
331 } else {
332 if (clipInStencil) {
333 switch (func) {
334 case kAlwaysIfInClip_StencilFunc:
335 *mask = clipBit;
336 *ref = clipBit;
337 break;
338 case kEqualIfInClip_StencilFunc:
339 case kLessIfInClip_StencilFunc:
340 case kLEqualIfInClip_StencilFunc:
341 *mask = (*mask & userBits) | clipBit;
342 *ref = (*ref & userBits) | clipBit;
343 break;
344 case kNonZeroIfInClip_StencilFunc:
345 *mask = (*mask & userBits) | clipBit;
346 *ref = clipBit;
347 break;
348 default:
349 GrCrash("Unknown stencil func");
350 }
351 } else {
352 *mask &= userBits;
353 *ref &= userBits;
354 }
355 }
356}
357
358////////////////////////////////////////////////////////////////////////////////
359
360#define VISUALIZE_COMPLEX_CLIP 0
361
362#if VISUALIZE_COMPLEX_CLIP
363 #include "GrRandom.h"
364 GrRandom gRandom;
365 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
366#else
367 #define SET_RANDOM_COLOR
368#endif
369
bsalomon@google.comffca4002011-02-22 20:34:01 +0000370bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000371 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000372 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000373
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000374 // we check this early because we need a valid
375 // render target to setup stencil clipping
376 // before even going into flushGraphicsState
377 if (NULL == fCurrDrawState.fRenderTarget) {
378 GrAssert(!"No render target bound.");
379 return false;
380 }
381
reed@google.comac10a2d2010-12-22 21:39:39 +0000382 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000383 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
384
385 GrRect bounds;
386 GrRect rtRect;
387 rtRect.setLTRB(0, 0,
388 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000389 if (fClip.hasConservativeBounds()) {
390 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000391 if (!bounds.intersect(rtRect)) {
392 bounds.setEmpty();
393 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000394 } else {
395 bounds = rtRect;
396 }
397
398 bounds.roundOut(&clipRect);
399 if (clipRect.isEmpty()) {
400 clipRect.setLTRB(0,0,0,0);
401 }
402 r = &clipRect;
403
404 fClipState.fClipInStencil = !fClip.isRect() &&
405 !fClip.isEmpty() &&
406 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000407
408 if (fClipState.fClipInStencil &&
409 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000410 fClip != rt.fLastStencilClip)) {
411
412 rt.fLastStencilClip = fClip;
413 // we set the current clip to the bounds so that our recursive
414 // draws are scissored to them. We use the copy of the complex clip
415 // in the rt to render
416 const GrClip& clip = rt.fLastStencilClip;
417 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000418
419 AutoStateRestore asr(this);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000420 AutoInternalDrawGeomRestore aidgr(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000421
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000422 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000423 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000424 this->flushScissor(NULL);
425#if !VISUALIZE_COMPLEX_CLIP
426 this->enableState(kNoColorWrites_StateBit);
427#else
428 this->disableState(kNoColorWrites_StateBit);
429#endif
430 int count = clip.getElementCount();
431 int clipBit = rt.stencilBits();
432 clipBit = (1 << (clipBit-1));
433
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000434 // often we'll see the first two elements of the clip are
435 // the full rt size and another element intersected with it.
436 // We can skip the first full-size rect and save a big rect draw.
437 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000438 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000439 kRect_ClipType == clip.getElementType(0) &&
440 kIntersect_SetOp == clip.getOp(1)&&
441 clip.getRect(0).contains(bounds)) {
442 firstElement = 1;
443 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000444
bsalomon@google.comd302f142011-03-03 13:54:13 +0000445 // walk through each clip element and perform its set op
446 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000447 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000448 GrPathFill fill;
449 // enabled at bottom of loop
450 this->disableState(kModifyStencilClip_StateBit);
451
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000452 bool canRenderDirectToStencil; // can the clip element be drawn
453 // directly to the stencil buffer
454 // with a non-inverted fill rule
455 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000456 // resolve in/out status.
457
458 GrPathRenderer* pr = NULL;
reed@google.com07f3ee12011-05-16 17:21:57 +0000459 const GrPath* clipPath = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000460 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000461 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000462 fill = kEvenOdd_PathFill;
463 } else {
464 fill = clip.getPathFill(c);
reed@google.com07f3ee12011-05-16 17:21:57 +0000465 clipPath = &clip.getPath(c);
466 pr = this->getClipPathRenderer(*clipPath, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000467 canRenderDirectToStencil =
reed@google.com07f3ee12011-05-16 17:21:57 +0000468 !pr->requiresStencilPass(this, *clipPath,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000469 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000470 }
471
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000472 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000473 int passes;
474 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
475
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000476 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000477 // fill rule, and set operation can
478 // we render the element directly to
479 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000480 canDrawDirectToClip =
481 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000482 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000483 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000484 IsFillInverted(fill),
485 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000486
487 // draw the element to the client stencil bits if necessary
488 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000489 static const GrStencilSettings gDrawToStencil = {
490 kIncClamp_StencilOp, kIncClamp_StencilOp,
491 kIncClamp_StencilOp, kIncClamp_StencilOp,
492 kAlways_StencilFunc, kAlways_StencilFunc,
493 0xffffffff, 0xffffffff,
494 0x00000000, 0x00000000,
495 0xffffffff, 0xffffffff,
496 };
497 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000498 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000499 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000500 this->drawSimpleRect(clip.getRect(c), NULL, 0);
501 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000502 if (canRenderDirectToStencil) {
503 this->setStencil(gDrawToStencil);
reed@google.com07f3ee12011-05-16 17:21:57 +0000504 pr->drawPath(this, 0, *clipPath, NonInvertedFill(fill),
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000505 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000506 } else {
reed@google.com07f3ee12011-05-16 17:21:57 +0000507 pr->drawPathToStencil(this, *clipPath,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000508 NonInvertedFill(fill),
509 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000510 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000511 }
512 }
513
514 // now we modify the clip bit by rendering either the clip
515 // element directly or a bounding rect of the entire clip.
516 this->enableState(kModifyStencilClip_StateBit);
517 for (int p = 0; p < passes; ++p) {
518 this->setStencil(stencilSettings[p]);
519 if (canDrawDirectToClip) {
520 if (kRect_ClipType == clip.getElementType(c)) {
521 SET_RANDOM_COLOR
522 this->drawSimpleRect(clip.getRect(c), NULL, 0);
523 } else {
524 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000525 GrAssert(!IsFillInverted(fill));
reed@google.com07f3ee12011-05-16 17:21:57 +0000526 pr->drawPath(this, 0, *clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000527 }
528 } else {
529 SET_RANDOM_COLOR
thakis@chromium.org441d7da2011-06-07 04:03:17 +0000530 this->drawSimpleRect(bounds, NULL, 0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000531 }
532 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000533 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000534 fClip = clip;
535 // recusive draws would have disabled this.
536 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000537 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000538
reed@google.comac10a2d2010-12-22 21:39:39 +0000539 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000540 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000541
reed@google.comac10a2d2010-12-22 21:39:39 +0000542 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000543 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000544 return false;
545 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000546 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000547 return true;
548}
549
reed@google.com07f3ee12011-05-16 17:21:57 +0000550GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000551 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000552 if (NULL != fClientPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000553 fClientPathRenderer->canDrawPath(this, path, fill)) {
554 return fClientPathRenderer;
555 } else {
556 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000557 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000558 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
559 this->supportsStencilWrapOps());
560 }
561 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
562 return fDefaultPathRenderer;
563 }
564}
565
566
bsalomon@google.comd302f142011-03-03 13:54:13 +0000567////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000568
bsalomon@google.comffca4002011-02-22 20:34:01 +0000569void GrGpu::drawIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000570 int startVertex,
571 int startIndex,
572 int vertexCount,
573 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000574 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
575 fReservedGeometry.fLocked);
576 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
577 fReservedGeometry.fLocked);
578
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000579 this->handleDirtyContext();
580
581 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000582 return;
583 }
584
585#if GR_COLLECT_STATS
586 fStats.fVertexCnt += vertexCount;
587 fStats.fIndexCnt += indexCount;
588 fStats.fDrawCnt += 1;
589#endif
590
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000591 int sVertex = startVertex;
592 int sIndex = startIndex;
593 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000594
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000595 this->onDrawIndexed(type, sVertex, sIndex,
596 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000597}
598
bsalomon@google.comffca4002011-02-22 20:34:01 +0000599void GrGpu::drawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000600 int startVertex,
601 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000602 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
603 fReservedGeometry.fLocked);
604
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000605 this->handleDirtyContext();
606
607 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000608 return;
609 }
610#if GR_COLLECT_STATS
611 fStats.fVertexCnt += vertexCount;
612 fStats.fDrawCnt += 1;
613#endif
614
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000615 int sVertex = startVertex;
616 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000617
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000618 this->onDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000619}
620
621void GrGpu::finalizeReservedVertices() {
622 GrAssert(NULL != fVertexPool);
623 fVertexPool->unlock();
624}
625
626void GrGpu::finalizeReservedIndices() {
627 GrAssert(NULL != fIndexPool);
628 fIndexPool->unlock();
629}
630
631void GrGpu::prepareVertexPool() {
632 if (NULL == fVertexPool) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000633 fVertexPool = new GrVertexBufferAllocPool(this, true,
634 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000635 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000636 fVertexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000637 } else if (!fVertexPoolInUse) {
638 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000639 fVertexPool->reset();
640 }
641}
642
643void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000644 if (NULL == fIndexPool) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000645 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000646 fIndexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000647 } else if (!fIndexPoolInUse) {
648 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000649 fIndexPool->reset();
650 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000651}
652
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000653bool GrGpu::onAcquireGeometry(GrVertexLayout vertexLayout,
654 void** vertices,
655 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000656 GrAssert(!fReservedGeometry.fLocked);
657 size_t reservedVertexSpace = 0;
658
659 if (fReservedGeometry.fVertexCount) {
660 GrAssert(NULL != vertices);
661
bsalomon@google.comd302f142011-03-03 13:54:13 +0000662 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000663
664 *vertices = fVertexPool->makeSpace(vertexLayout,
665 fReservedGeometry.fVertexCount,
666 &fCurrPoolVertexBuffer,
667 &fCurrPoolStartVertex);
668 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000669 return false;
670 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000671 reservedVertexSpace = VertexSize(vertexLayout) *
672 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000673 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000674 if (fReservedGeometry.fIndexCount) {
675 GrAssert(NULL != indices);
676
bsalomon@google.comd302f142011-03-03 13:54:13 +0000677 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000678
679 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
680 &fCurrPoolIndexBuffer,
681 &fCurrPoolStartIndex);
682 if (NULL == *indices) {
683 fVertexPool->putBack(reservedVertexSpace);
684 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000685 return false;
686 }
687 }
688 return true;
689}
690
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000691void GrGpu::onReleaseGeometry() {}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000692
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000693void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000694 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000695 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000696#if GR_DEBUG
697 bool success =
698#endif
699 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
700 vertexCount,
701 vertexArray,
702 &fCurrPoolVertexBuffer,
703 &fCurrPoolStartVertex);
704 GR_DEBUGASSERT(success);
705}
706
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000707void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000708 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000709 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000710#if GR_DEBUG
711 bool success =
712#endif
713 fIndexPool->appendIndices(indexCount,
714 indexArray,
715 &fCurrPoolIndexBuffer,
716 &fCurrPoolStartIndex);
717 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000718}
719
bsalomon@google.comd302f142011-03-03 13:54:13 +0000720////////////////////////////////////////////////////////////////////////////////
721
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000722const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000723 return fStats;
724}
725
726void GrGpu::resetStats() {
727 memset(&fStats, 0, sizeof(fStats));
728}
729
730void GrGpu::printStats() const {
731 if (GR_COLLECT_STATS) {
732 GrPrintf(
733 "-v-------------------------GPU STATS----------------------------v-\n"
734 "Stats collection is: %s\n"
735 "Draws: %04d, Verts: %04d, Indices: %04d\n"
736 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
737 "TexCreates: %04d, RTCreates:%04d\n"
738 "-^--------------------------------------------------------------^-\n",
739 (GR_COLLECT_STATS ? "ON" : "OFF"),
740 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
741 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
742 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
743 }
744}
745
746////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000747const GrSamplerState GrSamplerState::gClampNoFilter(
748 GrSamplerState::kClamp_WrapMode,
749 GrSamplerState::kClamp_WrapMode,
750 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000751 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000752 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000753
754
755
756