blob: 06de3ac53ce5a1fd38bd8af4b7b3722052b6fe4d [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.coma7f84e12011-03-10 14:13:19 +0000139GrTexture* GrGpu::createTexture(const TextureDesc& desc,
140 const void* srcData, size_t rowBytes) {
141 this->handleDirtyContext();
142 return this->createTextureHelper(desc, srcData, rowBytes);
143}
144
145GrRenderTarget* GrGpu::createPlatformRenderTarget(intptr_t platformRenderTarget,
146 int stencilBits,
147 int width, int height) {
148 this->handleDirtyContext();
149 return this->createPlatformRenderTargetHelper(platformRenderTarget,
150 stencilBits,
151 width, height);
152}
153
154GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
155 this->handleDirtyContext();
156 return this->createRenderTargetFrom3DApiStateHelper();
157}
158
159GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
160 this->handleDirtyContext();
161 return this->createVertexBufferHelper(size, dynamic);
162}
163
164GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
165 this->handleDirtyContext();
166 return this->createIndexBufferHelper(size, dynamic);
167}
168
169void GrGpu::eraseColor(GrColor color) {
170 this->handleDirtyContext();
171 this->eraseColorHelper(color);
172}
173
174void GrGpu::forceRenderTargetFlush() {
175 this->handleDirtyContext();
176 this->forceRenderTargetFlushHelper();
177}
178
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000179bool GrGpu::readPixels(GrRenderTarget* target,
180 int left, int top, int width, int height,
181 GrPixelConfig config, void* buffer) {
182
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000183 this->handleDirtyContext();
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000184 GrRenderTarget* prevTarget = fCurrDrawState.fRenderTarget;
185 if (NULL != target) {
186 fCurrDrawState.fRenderTarget = target;
187 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000188 return this->readPixelsHelper(left, top, width, height, config, buffer);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000189 fCurrDrawState.fRenderTarget = prevTarget;
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000190}
191
192////////////////////////////////////////////////////////////////////////////////
193
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000194static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000195
reed@google.com8195f672011-01-12 18:14:28 +0000196GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000197
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000198static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000199 for (int i = 0; i < quadCount; ++i) {
200 indices[6 * i + 0] = 4 * i + 0;
201 indices[6 * i + 1] = 4 * i + 1;
202 indices[6 * i + 2] = 4 * i + 2;
203 indices[6 * i + 3] = 4 * i + 0;
204 indices[6 * i + 4] = 4 * i + 2;
205 indices[6 * i + 5] = 4 * i + 3;
206 }
207}
208
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000209const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000210 if (NULL == fQuadIndexBuffer) {
211 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
212 GrGpu* me = const_cast<GrGpu*>(this);
213 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
214 if (NULL != fQuadIndexBuffer) {
215 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
216 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000217 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000218 fQuadIndexBuffer->unlock();
219 } else {
220 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000221 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000222 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
223 fQuadIndexBuffer->unref();
224 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000225 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000226 }
227 GrFree(indices);
228 }
229 }
230 }
231
232 return fQuadIndexBuffer;
233}
234
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000235const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000236 if (NULL == fUnitSquareVertexBuffer) {
237
238 static const GrPoint DATA[] = {
239 GrPoint(0, 0),
240 GrPoint(GR_Scalar1,0),
241 GrPoint(GR_Scalar1,GR_Scalar1),
242 GrPoint(0, GR_Scalar1)
243 };
244 static const size_t SIZE = sizeof(DATA);
245
246 GrGpu* me = const_cast<GrGpu*>(this);
247 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
248 if (NULL != fUnitSquareVertexBuffer) {
249 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
250 fUnitSquareVertexBuffer->unref();
251 fUnitSquareVertexBuffer = NULL;
252 GrCrash("Can't get vertices into buffer!");
253 }
254 }
255 }
256
257 return fUnitSquareVertexBuffer;
258}
259
bsalomon@google.comd302f142011-03-03 13:54:13 +0000260////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000261
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000262void GrGpu::clipWillBeSet(const GrClip& newClip) {
263 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000264 fClipState.fClipIsDirty = true;
265 }
266}
267
bsalomon@google.comd302f142011-03-03 13:54:13 +0000268////////////////////////////////////////////////////////////////////////////////
269
270// stencil settings to use when clip is in stencil
271const GrStencilSettings GrGpu::gClipStencilSettings = {
272 kKeep_StencilOp, kKeep_StencilOp,
273 kKeep_StencilOp, kKeep_StencilOp,
274 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
275 0, 0,
276 0, 0,
277 0, 0
278};
279
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000280// mapping of clip-respecting stencil funcs to normal stencil funcs
281// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000282static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
283 {// Stencil-Clipping is DISABLED, effectively always inside the clip
284 // In the Clip Funcs
285 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
286 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
287 kLess_StencilFunc, // kLessIfInClip_StencilFunc
288 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
289 // Special in the clip func that forces user's ref to be 0.
290 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
291 // make ref 0 and do normal nequal.
292 },
293 {// Stencil-Clipping is ENABLED
294 // In the Clip Funcs
295 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
296 // eq stencil clip bit, mask
297 // out user bits.
298
299 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
300 // add stencil bit to mask and ref
301
302 kLess_StencilFunc, // kLessIfInClip_StencilFunc
303 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
304 // for both of these we can add
305 // the clip bit to the mask and
306 // ref and compare as normal
307 // Special in the clip func that forces user's ref to be 0.
308 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
309 // make ref have only the clip bit set
310 // and make comparison be less
311 // 10..0 < 1..user_bits..
312 }
313};
314
315GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
316 GrAssert(func >= 0);
317 if (func >= kBasicStencilFuncCount) {
318 GrAssert(func < kStencilFuncCount);
319 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
320 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
321 }
322 return func;
323}
324
325void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
326 bool clipInStencil,
327 unsigned int clipBit,
328 unsigned int userBits,
329 unsigned int* ref,
330 unsigned int* mask) {
331 if (func < kBasicStencilFuncCount) {
332 *mask &= userBits;
333 *ref &= userBits;
334 } else {
335 if (clipInStencil) {
336 switch (func) {
337 case kAlwaysIfInClip_StencilFunc:
338 *mask = clipBit;
339 *ref = clipBit;
340 break;
341 case kEqualIfInClip_StencilFunc:
342 case kLessIfInClip_StencilFunc:
343 case kLEqualIfInClip_StencilFunc:
344 *mask = (*mask & userBits) | clipBit;
345 *ref = (*ref & userBits) | clipBit;
346 break;
347 case kNonZeroIfInClip_StencilFunc:
348 *mask = (*mask & userBits) | clipBit;
349 *ref = clipBit;
350 break;
351 default:
352 GrCrash("Unknown stencil func");
353 }
354 } else {
355 *mask &= userBits;
356 *ref &= userBits;
357 }
358 }
359}
360
361////////////////////////////////////////////////////////////////////////////////
362
363#define VISUALIZE_COMPLEX_CLIP 0
364
365#if VISUALIZE_COMPLEX_CLIP
366 #include "GrRandom.h"
367 GrRandom gRandom;
368 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
369#else
370 #define SET_RANDOM_COLOR
371#endif
372
bsalomon@google.comffca4002011-02-22 20:34:01 +0000373bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000374 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000375 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000376
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000377 // we check this early because we need a valid
378 // render target to setup stencil clipping
379 // before even going into flushGraphicsState
380 if (NULL == fCurrDrawState.fRenderTarget) {
381 GrAssert(!"No render target bound.");
382 return false;
383 }
384
reed@google.comac10a2d2010-12-22 21:39:39 +0000385 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000386 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
387
388 GrRect bounds;
389 GrRect rtRect;
390 rtRect.setLTRB(0, 0,
391 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000392 if (fClip.hasConservativeBounds()) {
393 bounds = fClip.getConservativeBounds();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000394 bounds.intersectWith(rtRect);
395 } else {
396 bounds = rtRect;
397 }
398
399 bounds.roundOut(&clipRect);
400 if (clipRect.isEmpty()) {
401 clipRect.setLTRB(0,0,0,0);
402 }
403 r = &clipRect;
404
405 fClipState.fClipInStencil = !fClip.isRect() &&
406 !fClip.isEmpty() &&
407 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000408
409 if (fClipState.fClipInStencil &&
410 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000411 fClip != rt.fLastStencilClip)) {
412
413 rt.fLastStencilClip = fClip;
414 // we set the current clip to the bounds so that our recursive
415 // draws are scissored to them. We use the copy of the complex clip
416 // in the rt to render
417 const GrClip& clip = rt.fLastStencilClip;
418 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000419
420 AutoStateRestore asr(this);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000421 AutoInternalDrawGeomRestore aidgr(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000422
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000423 this->setViewMatrix(GrMatrix::I());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000424 this->eraseStencilClip(clipRect);
425 this->flushScissor(NULL);
426#if !VISUALIZE_COMPLEX_CLIP
427 this->enableState(kNoColorWrites_StateBit);
428#else
429 this->disableState(kNoColorWrites_StateBit);
430#endif
431 int count = clip.getElementCount();
432 int clipBit = rt.stencilBits();
433 clipBit = (1 << (clipBit-1));
434
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000435 // often we'll see the first two elements of the clip are
436 // the full rt size and another element intersected with it.
437 // We can skip the first full-size rect and save a big rect draw.
438 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000439 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000440 kRect_ClipType == clip.getElementType(0) &&
441 kIntersect_SetOp == clip.getOp(1)&&
442 clip.getRect(0).contains(bounds)) {
443 firstElement = 1;
444 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000445
bsalomon@google.comd302f142011-03-03 13:54:13 +0000446 // walk through each clip element and perform its set op
447 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000448 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000449 GrPathFill fill;
450 // enabled at bottom of loop
451 this->disableState(kModifyStencilClip_StateBit);
452
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000453 bool canRenderDirectToStencil; // can the clip element be drawn
454 // directly to the stencil buffer
455 // with a non-inverted fill rule
456 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000457 // resolve in/out status.
458
459 GrPathRenderer* pr = NULL;
460 GrPath::Iter pathIter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000461 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000462 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000463 fill = kEvenOdd_PathFill;
464 } else {
465 fill = clip.getPathFill(c);
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000466 const GrPath& path = clip.getPath(c);
467 pathIter.reset(path);
468 pr = this->getClipPathRenderer(&pathIter, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000469 canRenderDirectToStencil =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000470 !pr->requiresStencilPass(this, &pathIter,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000471 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000472 }
473
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000474 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000475 int passes;
476 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
477
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000478 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000479 // fill rule, and set operation can
480 // we render the element directly to
481 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000482 canDrawDirectToClip =
483 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000484 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000485 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000486 IsFillInverted(fill),
487 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000488
489 // draw the element to the client stencil bits if necessary
490 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000491 static const GrStencilSettings gDrawToStencil = {
492 kIncClamp_StencilOp, kIncClamp_StencilOp,
493 kIncClamp_StencilOp, kIncClamp_StencilOp,
494 kAlways_StencilFunc, kAlways_StencilFunc,
495 0xffffffff, 0xffffffff,
496 0x00000000, 0x00000000,
497 0xffffffff, 0xffffffff,
498 };
499 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000500 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000501 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000502 this->drawSimpleRect(clip.getRect(c), NULL, 0);
503 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000504 if (canRenderDirectToStencil) {
505 this->setStencil(gDrawToStencil);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000506 pr->drawPath(this, 0,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000507 &pathIter,
508 NonInvertedFill(fill),
509 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000510 } else {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000511 pr->drawPathToStencil(this, &pathIter,
512 NonInvertedFill(fill),
513 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000514 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000515 }
516 }
517
518 // now we modify the clip bit by rendering either the clip
519 // element directly or a bounding rect of the entire clip.
520 this->enableState(kModifyStencilClip_StateBit);
521 for (int p = 0; p < passes; ++p) {
522 this->setStencil(stencilSettings[p]);
523 if (canDrawDirectToClip) {
524 if (kRect_ClipType == clip.getElementType(c)) {
525 SET_RANDOM_COLOR
526 this->drawSimpleRect(clip.getRect(c), NULL, 0);
527 } else {
528 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000529 GrAssert(!IsFillInverted(fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000530 pr->drawPath(this, 0, &pathIter, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000531 }
532 } else {
533 SET_RANDOM_COLOR
534 this->drawSimpleRect(bounds, 0, NULL);
535 }
536 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000537 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000538 fClip = clip;
539 // recusive draws would have disabled this.
540 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000541 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000542
reed@google.comac10a2d2010-12-22 21:39:39 +0000543 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000544 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000545
reed@google.comac10a2d2010-12-22 21:39:39 +0000546 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000547 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000548 return false;
549 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000550 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000551 return true;
552}
553
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000554GrPathRenderer* GrGpu::getClipPathRenderer(GrPathIter* path,
555 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000556 if (NULL != fClientPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000557 fClientPathRenderer->canDrawPath(this, path, fill)) {
558 return fClientPathRenderer;
559 } else {
560 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000561 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000562 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
563 this->supportsStencilWrapOps());
564 }
565 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
566 return fDefaultPathRenderer;
567 }
568}
569
570
bsalomon@google.comd302f142011-03-03 13:54:13 +0000571////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000572
bsalomon@google.comffca4002011-02-22 20:34:01 +0000573void GrGpu::drawIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000574 int startVertex,
575 int startIndex,
576 int vertexCount,
577 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000578 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
579 fReservedGeometry.fLocked);
580 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
581 fReservedGeometry.fLocked);
582
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000583 this->handleDirtyContext();
584
585 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000586 return;
587 }
588
589#if GR_COLLECT_STATS
590 fStats.fVertexCnt += vertexCount;
591 fStats.fIndexCnt += indexCount;
592 fStats.fDrawCnt += 1;
593#endif
594
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000595 int sVertex = startVertex;
596 int sIndex = startIndex;
597 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000598
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000599 drawIndexedHelper(type, sVertex, sIndex,
reed@google.comac10a2d2010-12-22 21:39:39 +0000600 vertexCount, indexCount);
601}
602
bsalomon@google.comffca4002011-02-22 20:34:01 +0000603void GrGpu::drawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000604 int startVertex,
605 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000606 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
607 fReservedGeometry.fLocked);
608
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000609 this->handleDirtyContext();
610
611 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000612 return;
613 }
614#if GR_COLLECT_STATS
615 fStats.fVertexCnt += vertexCount;
616 fStats.fDrawCnt += 1;
617#endif
618
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000619 int sVertex = startVertex;
620 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000621
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000622 drawNonIndexedHelper(type, sVertex, vertexCount);
623}
624
625void GrGpu::finalizeReservedVertices() {
626 GrAssert(NULL != fVertexPool);
627 fVertexPool->unlock();
628}
629
630void GrGpu::finalizeReservedIndices() {
631 GrAssert(NULL != fIndexPool);
632 fIndexPool->unlock();
633}
634
635void GrGpu::prepareVertexPool() {
636 if (NULL == fVertexPool) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000637 fVertexPool = new GrVertexBufferAllocPool(this, true,
638 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000639 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000640 fVertexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000641 } else if (!fVertexPoolInUse) {
642 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000643 fVertexPool->reset();
644 }
645}
646
647void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000648 if (NULL == fIndexPool) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000649 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000650 fIndexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000651 } else if (!fIndexPoolInUse) {
652 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000653 fIndexPool->reset();
654 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000655}
656
657bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout,
658 void** vertices,
659 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000660 GrAssert(!fReservedGeometry.fLocked);
661 size_t reservedVertexSpace = 0;
662
663 if (fReservedGeometry.fVertexCount) {
664 GrAssert(NULL != vertices);
665
bsalomon@google.comd302f142011-03-03 13:54:13 +0000666 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000667
668 *vertices = fVertexPool->makeSpace(vertexLayout,
669 fReservedGeometry.fVertexCount,
670 &fCurrPoolVertexBuffer,
671 &fCurrPoolStartVertex);
672 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000673 return false;
674 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000675 reservedVertexSpace = VertexSize(vertexLayout) *
676 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000677 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000678 if (fReservedGeometry.fIndexCount) {
679 GrAssert(NULL != indices);
680
bsalomon@google.comd302f142011-03-03 13:54:13 +0000681 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000682
683 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
684 &fCurrPoolIndexBuffer,
685 &fCurrPoolStartIndex);
686 if (NULL == *indices) {
687 fVertexPool->putBack(reservedVertexSpace);
688 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000689 return false;
690 }
691 }
692 return true;
693}
694
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000695void GrGpu::releaseGeometryHelper() {}
696
697void GrGpu::setVertexSourceToArrayHelper(const void* vertexArray, int vertexCount) {
698 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
699 prepareVertexPool();
700#if GR_DEBUG
701 bool success =
702#endif
703 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
704 vertexCount,
705 vertexArray,
706 &fCurrPoolVertexBuffer,
707 &fCurrPoolStartVertex);
708 GR_DEBUGASSERT(success);
709}
710
711void GrGpu::setIndexSourceToArrayHelper(const void* indexArray, int indexCount) {
712 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
713 prepareIndexPool();
714#if GR_DEBUG
715 bool success =
716#endif
717 fIndexPool->appendIndices(indexCount,
718 indexArray,
719 &fCurrPoolIndexBuffer,
720 &fCurrPoolStartIndex);
721 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000722}
723
bsalomon@google.comd302f142011-03-03 13:54:13 +0000724////////////////////////////////////////////////////////////////////////////////
725
reed@google.comac10a2d2010-12-22 21:39:39 +0000726const GrGpu::Stats& GrGpu::getStats() const {
727 return fStats;
728}
729
730void GrGpu::resetStats() {
731 memset(&fStats, 0, sizeof(fStats));
732}
733
734void GrGpu::printStats() const {
735 if (GR_COLLECT_STATS) {
736 GrPrintf(
737 "-v-------------------------GPU STATS----------------------------v-\n"
738 "Stats collection is: %s\n"
739 "Draws: %04d, Verts: %04d, Indices: %04d\n"
740 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
741 "TexCreates: %04d, RTCreates:%04d\n"
742 "-^--------------------------------------------------------------^-\n",
743 (GR_COLLECT_STATS ? "ON" : "OFF"),
744 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
745 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
746 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
747 }
748}
749
750////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000751const GrSamplerState GrSamplerState::gClampNoFilter(
752 GrSamplerState::kClamp_WrapMode,
753 GrSamplerState::kClamp_WrapMode,
754 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000755 GrMatrix::I(),
reed@google.comac10a2d2010-12-22 21:39:39 +0000756 false);
757
758
759
760