blob: 9950afd27b9fe402c8799f417c97ce8a57e378f6 [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[] = {
reed@google.com7744c202011-05-06 19:26:26 +0000241 { 0, 0 },
242 { GR_Scalar1, 0 },
243 { GR_Scalar1, GR_Scalar1 },
244 { 0, GR_Scalar1 }
245#if 0
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000246 GrPoint(0, 0),
247 GrPoint(GR_Scalar1,0),
248 GrPoint(GR_Scalar1,GR_Scalar1),
249 GrPoint(0, GR_Scalar1)
reed@google.com7744c202011-05-06 19:26:26 +0000250#endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000251 };
252 static const size_t SIZE = sizeof(DATA);
253
254 GrGpu* me = const_cast<GrGpu*>(this);
255 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
256 if (NULL != fUnitSquareVertexBuffer) {
257 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
258 fUnitSquareVertexBuffer->unref();
259 fUnitSquareVertexBuffer = NULL;
260 GrCrash("Can't get vertices into buffer!");
261 }
262 }
263 }
264
265 return fUnitSquareVertexBuffer;
266}
267
bsalomon@google.comd302f142011-03-03 13:54:13 +0000268////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000269
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000270void GrGpu::clipWillBeSet(const GrClip& newClip) {
271 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000272 fClipState.fClipIsDirty = true;
273 }
274}
275
bsalomon@google.comd302f142011-03-03 13:54:13 +0000276////////////////////////////////////////////////////////////////////////////////
277
278// stencil settings to use when clip is in stencil
279const GrStencilSettings GrGpu::gClipStencilSettings = {
280 kKeep_StencilOp, kKeep_StencilOp,
281 kKeep_StencilOp, kKeep_StencilOp,
282 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
283 0, 0,
284 0, 0,
285 0, 0
286};
287
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000288// mapping of clip-respecting stencil funcs to normal stencil funcs
289// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000290static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
291 {// Stencil-Clipping is DISABLED, effectively always inside the clip
292 // In the Clip Funcs
293 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
294 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
295 kLess_StencilFunc, // kLessIfInClip_StencilFunc
296 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
297 // Special in the clip func that forces user's ref to be 0.
298 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
299 // make ref 0 and do normal nequal.
300 },
301 {// Stencil-Clipping is ENABLED
302 // In the Clip Funcs
303 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
304 // eq stencil clip bit, mask
305 // out user bits.
306
307 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
308 // add stencil bit to mask and ref
309
310 kLess_StencilFunc, // kLessIfInClip_StencilFunc
311 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
312 // for both of these we can add
313 // the clip bit to the mask and
314 // ref and compare as normal
315 // Special in the clip func that forces user's ref to be 0.
316 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
317 // make ref have only the clip bit set
318 // and make comparison be less
319 // 10..0 < 1..user_bits..
320 }
321};
322
323GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
324 GrAssert(func >= 0);
325 if (func >= kBasicStencilFuncCount) {
326 GrAssert(func < kStencilFuncCount);
327 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
328 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
329 }
330 return func;
331}
332
333void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
334 bool clipInStencil,
335 unsigned int clipBit,
336 unsigned int userBits,
337 unsigned int* ref,
338 unsigned int* mask) {
339 if (func < kBasicStencilFuncCount) {
340 *mask &= userBits;
341 *ref &= userBits;
342 } else {
343 if (clipInStencil) {
344 switch (func) {
345 case kAlwaysIfInClip_StencilFunc:
346 *mask = clipBit;
347 *ref = clipBit;
348 break;
349 case kEqualIfInClip_StencilFunc:
350 case kLessIfInClip_StencilFunc:
351 case kLEqualIfInClip_StencilFunc:
352 *mask = (*mask & userBits) | clipBit;
353 *ref = (*ref & userBits) | clipBit;
354 break;
355 case kNonZeroIfInClip_StencilFunc:
356 *mask = (*mask & userBits) | clipBit;
357 *ref = clipBit;
358 break;
359 default:
360 GrCrash("Unknown stencil func");
361 }
362 } else {
363 *mask &= userBits;
364 *ref &= userBits;
365 }
366 }
367}
368
369////////////////////////////////////////////////////////////////////////////////
370
371#define VISUALIZE_COMPLEX_CLIP 0
372
373#if VISUALIZE_COMPLEX_CLIP
374 #include "GrRandom.h"
375 GrRandom gRandom;
376 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
377#else
378 #define SET_RANDOM_COLOR
379#endif
380
bsalomon@google.comffca4002011-02-22 20:34:01 +0000381bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000382 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000383 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000384
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000385 // we check this early because we need a valid
386 // render target to setup stencil clipping
387 // before even going into flushGraphicsState
388 if (NULL == fCurrDrawState.fRenderTarget) {
389 GrAssert(!"No render target bound.");
390 return false;
391 }
392
reed@google.comac10a2d2010-12-22 21:39:39 +0000393 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000394 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
395
396 GrRect bounds;
397 GrRect rtRect;
398 rtRect.setLTRB(0, 0,
399 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000400 if (fClip.hasConservativeBounds()) {
401 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000402 if (!bounds.intersect(rtRect)) {
403 bounds.setEmpty();
404 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000405 } else {
406 bounds = rtRect;
407 }
408
409 bounds.roundOut(&clipRect);
410 if (clipRect.isEmpty()) {
411 clipRect.setLTRB(0,0,0,0);
412 }
413 r = &clipRect;
414
415 fClipState.fClipInStencil = !fClip.isRect() &&
416 !fClip.isEmpty() &&
417 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000418
419 if (fClipState.fClipInStencil &&
420 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000421 fClip != rt.fLastStencilClip)) {
422
423 rt.fLastStencilClip = fClip;
424 // we set the current clip to the bounds so that our recursive
425 // draws are scissored to them. We use the copy of the complex clip
426 // in the rt to render
427 const GrClip& clip = rt.fLastStencilClip;
428 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000429
430 AutoStateRestore asr(this);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000431 AutoInternalDrawGeomRestore aidgr(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000432
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000433 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000434 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000435 this->flushScissor(NULL);
436#if !VISUALIZE_COMPLEX_CLIP
437 this->enableState(kNoColorWrites_StateBit);
438#else
439 this->disableState(kNoColorWrites_StateBit);
440#endif
441 int count = clip.getElementCount();
442 int clipBit = rt.stencilBits();
443 clipBit = (1 << (clipBit-1));
444
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000445 // often we'll see the first two elements of the clip are
446 // the full rt size and another element intersected with it.
447 // We can skip the first full-size rect and save a big rect draw.
448 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000449 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000450 kRect_ClipType == clip.getElementType(0) &&
451 kIntersect_SetOp == clip.getOp(1)&&
452 clip.getRect(0).contains(bounds)) {
453 firstElement = 1;
454 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000455
bsalomon@google.comd302f142011-03-03 13:54:13 +0000456 // walk through each clip element and perform its set op
457 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000458 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000459 GrPathFill fill;
460 // enabled at bottom of loop
461 this->disableState(kModifyStencilClip_StateBit);
462
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000463 bool canRenderDirectToStencil; // can the clip element be drawn
464 // directly to the stencil buffer
465 // with a non-inverted fill rule
466 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000467 // resolve in/out status.
468
469 GrPathRenderer* pr = NULL;
470 GrPath::Iter pathIter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000471 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000472 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000473 fill = kEvenOdd_PathFill;
474 } else {
475 fill = clip.getPathFill(c);
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000476 const GrPath& path = clip.getPath(c);
477 pathIter.reset(path);
478 pr = this->getClipPathRenderer(&pathIter, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000479 canRenderDirectToStencil =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000480 !pr->requiresStencilPass(this, &pathIter,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000481 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000482 }
483
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000484 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000485 int passes;
486 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
487
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000488 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000489 // fill rule, and set operation can
490 // we render the element directly to
491 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000492 canDrawDirectToClip =
493 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000494 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000495 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000496 IsFillInverted(fill),
497 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000498
499 // draw the element to the client stencil bits if necessary
500 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000501 static const GrStencilSettings gDrawToStencil = {
502 kIncClamp_StencilOp, kIncClamp_StencilOp,
503 kIncClamp_StencilOp, kIncClamp_StencilOp,
504 kAlways_StencilFunc, kAlways_StencilFunc,
505 0xffffffff, 0xffffffff,
506 0x00000000, 0x00000000,
507 0xffffffff, 0xffffffff,
508 };
509 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000510 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000511 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000512 this->drawSimpleRect(clip.getRect(c), NULL, 0);
513 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000514 if (canRenderDirectToStencil) {
515 this->setStencil(gDrawToStencil);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000516 pr->drawPath(this, 0,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000517 &pathIter,
518 NonInvertedFill(fill),
519 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000520 } else {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000521 pr->drawPathToStencil(this, &pathIter,
522 NonInvertedFill(fill),
523 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000524 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000525 }
526 }
527
528 // now we modify the clip bit by rendering either the clip
529 // element directly or a bounding rect of the entire clip.
530 this->enableState(kModifyStencilClip_StateBit);
531 for (int p = 0; p < passes; ++p) {
532 this->setStencil(stencilSettings[p]);
533 if (canDrawDirectToClip) {
534 if (kRect_ClipType == clip.getElementType(c)) {
535 SET_RANDOM_COLOR
536 this->drawSimpleRect(clip.getRect(c), NULL, 0);
537 } else {
538 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000539 GrAssert(!IsFillInverted(fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000540 pr->drawPath(this, 0, &pathIter, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000541 }
542 } else {
543 SET_RANDOM_COLOR
544 this->drawSimpleRect(bounds, 0, NULL);
545 }
546 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000547 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000548 fClip = clip;
549 // recusive draws would have disabled this.
550 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000551 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000552
reed@google.comac10a2d2010-12-22 21:39:39 +0000553 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000554 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000555
reed@google.comac10a2d2010-12-22 21:39:39 +0000556 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000557 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000558 return false;
559 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000560 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000561 return true;
562}
563
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000564GrPathRenderer* GrGpu::getClipPathRenderer(GrPathIter* path,
565 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000566 if (NULL != fClientPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000567 fClientPathRenderer->canDrawPath(this, path, fill)) {
568 return fClientPathRenderer;
569 } else {
570 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000571 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000572 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
573 this->supportsStencilWrapOps());
574 }
575 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
576 return fDefaultPathRenderer;
577 }
578}
579
580
bsalomon@google.comd302f142011-03-03 13:54:13 +0000581////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000582
bsalomon@google.comffca4002011-02-22 20:34:01 +0000583void GrGpu::drawIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000584 int startVertex,
585 int startIndex,
586 int vertexCount,
587 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000588 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
589 fReservedGeometry.fLocked);
590 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
591 fReservedGeometry.fLocked);
592
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000593 this->handleDirtyContext();
594
595 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000596 return;
597 }
598
599#if GR_COLLECT_STATS
600 fStats.fVertexCnt += vertexCount;
601 fStats.fIndexCnt += indexCount;
602 fStats.fDrawCnt += 1;
603#endif
604
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000605 int sVertex = startVertex;
606 int sIndex = startIndex;
607 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000608
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000609 this->onDrawIndexed(type, sVertex, sIndex,
610 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000611}
612
bsalomon@google.comffca4002011-02-22 20:34:01 +0000613void GrGpu::drawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000614 int startVertex,
615 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000616 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
617 fReservedGeometry.fLocked);
618
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000619 this->handleDirtyContext();
620
621 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000622 return;
623 }
624#if GR_COLLECT_STATS
625 fStats.fVertexCnt += vertexCount;
626 fStats.fDrawCnt += 1;
627#endif
628
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000629 int sVertex = startVertex;
630 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000631
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000632 this->onDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000633}
634
635void GrGpu::finalizeReservedVertices() {
636 GrAssert(NULL != fVertexPool);
637 fVertexPool->unlock();
638}
639
640void GrGpu::finalizeReservedIndices() {
641 GrAssert(NULL != fIndexPool);
642 fIndexPool->unlock();
643}
644
645void GrGpu::prepareVertexPool() {
646 if (NULL == fVertexPool) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000647 fVertexPool = new GrVertexBufferAllocPool(this, true,
648 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000649 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000650 fVertexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000651 } else if (!fVertexPoolInUse) {
652 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000653 fVertexPool->reset();
654 }
655}
656
657void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000658 if (NULL == fIndexPool) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000659 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000660 fIndexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000661 } else if (!fIndexPoolInUse) {
662 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000663 fIndexPool->reset();
664 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000665}
666
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000667bool GrGpu::onAcquireGeometry(GrVertexLayout vertexLayout,
668 void** vertices,
669 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000670 GrAssert(!fReservedGeometry.fLocked);
671 size_t reservedVertexSpace = 0;
672
673 if (fReservedGeometry.fVertexCount) {
674 GrAssert(NULL != vertices);
675
bsalomon@google.comd302f142011-03-03 13:54:13 +0000676 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000677
678 *vertices = fVertexPool->makeSpace(vertexLayout,
679 fReservedGeometry.fVertexCount,
680 &fCurrPoolVertexBuffer,
681 &fCurrPoolStartVertex);
682 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000683 return false;
684 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000685 reservedVertexSpace = VertexSize(vertexLayout) *
686 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000687 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000688 if (fReservedGeometry.fIndexCount) {
689 GrAssert(NULL != indices);
690
bsalomon@google.comd302f142011-03-03 13:54:13 +0000691 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000692
693 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
694 &fCurrPoolIndexBuffer,
695 &fCurrPoolStartIndex);
696 if (NULL == *indices) {
697 fVertexPool->putBack(reservedVertexSpace);
698 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000699 return false;
700 }
701 }
702 return true;
703}
704
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000705void GrGpu::onReleaseGeometry() {}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000706
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000707void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000708 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000709 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000710#if GR_DEBUG
711 bool success =
712#endif
713 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
714 vertexCount,
715 vertexArray,
716 &fCurrPoolVertexBuffer,
717 &fCurrPoolStartVertex);
718 GR_DEBUGASSERT(success);
719}
720
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000721void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000722 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000723 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000724#if GR_DEBUG
725 bool success =
726#endif
727 fIndexPool->appendIndices(indexCount,
728 indexArray,
729 &fCurrPoolIndexBuffer,
730 &fCurrPoolStartIndex);
731 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000732}
733
bsalomon@google.comd302f142011-03-03 13:54:13 +0000734////////////////////////////////////////////////////////////////////////////////
735
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000736const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000737 return fStats;
738}
739
740void GrGpu::resetStats() {
741 memset(&fStats, 0, sizeof(fStats));
742}
743
744void GrGpu::printStats() const {
745 if (GR_COLLECT_STATS) {
746 GrPrintf(
747 "-v-------------------------GPU STATS----------------------------v-\n"
748 "Stats collection is: %s\n"
749 "Draws: %04d, Verts: %04d, Indices: %04d\n"
750 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
751 "TexCreates: %04d, RTCreates:%04d\n"
752 "-^--------------------------------------------------------------^-\n",
753 (GR_COLLECT_STATS ? "ON" : "OFF"),
754 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
755 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
756 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
757 }
758}
759
760////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000761const GrSamplerState GrSamplerState::gClampNoFilter(
762 GrSamplerState::kClamp_WrapMode,
763 GrSamplerState::kClamp_WrapMode,
764 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000765 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000766 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000767
768
769
770