blob: a64a8dbedc7d42a8b5a513c0448f629e3c903137 [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;
reed@google.com07f3ee12011-05-16 17:21:57 +0000470 const GrPath* clipPath = NULL;
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);
reed@google.com07f3ee12011-05-16 17:21:57 +0000476 clipPath = &clip.getPath(c);
477 pr = this->getClipPathRenderer(*clipPath, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000478 canRenderDirectToStencil =
reed@google.com07f3ee12011-05-16 17:21:57 +0000479 !pr->requiresStencilPass(this, *clipPath,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000480 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000481 }
482
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000483 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000484 int passes;
485 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
486
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000487 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000488 // fill rule, and set operation can
489 // we render the element directly to
490 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000491 canDrawDirectToClip =
492 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000493 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000494 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000495 IsFillInverted(fill),
496 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000497
498 // draw the element to the client stencil bits if necessary
499 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000500 static const GrStencilSettings gDrawToStencil = {
501 kIncClamp_StencilOp, kIncClamp_StencilOp,
502 kIncClamp_StencilOp, kIncClamp_StencilOp,
503 kAlways_StencilFunc, kAlways_StencilFunc,
504 0xffffffff, 0xffffffff,
505 0x00000000, 0x00000000,
506 0xffffffff, 0xffffffff,
507 };
508 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000509 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000510 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000511 this->drawSimpleRect(clip.getRect(c), NULL, 0);
512 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000513 if (canRenderDirectToStencil) {
514 this->setStencil(gDrawToStencil);
reed@google.com07f3ee12011-05-16 17:21:57 +0000515 pr->drawPath(this, 0, *clipPath, NonInvertedFill(fill),
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000516 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000517 } else {
reed@google.com07f3ee12011-05-16 17:21:57 +0000518 pr->drawPathToStencil(this, *clipPath,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000519 NonInvertedFill(fill),
520 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000521 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000522 }
523 }
524
525 // now we modify the clip bit by rendering either the clip
526 // element directly or a bounding rect of the entire clip.
527 this->enableState(kModifyStencilClip_StateBit);
528 for (int p = 0; p < passes; ++p) {
529 this->setStencil(stencilSettings[p]);
530 if (canDrawDirectToClip) {
531 if (kRect_ClipType == clip.getElementType(c)) {
532 SET_RANDOM_COLOR
533 this->drawSimpleRect(clip.getRect(c), NULL, 0);
534 } else {
535 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000536 GrAssert(!IsFillInverted(fill));
reed@google.com07f3ee12011-05-16 17:21:57 +0000537 pr->drawPath(this, 0, *clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000538 }
539 } else {
540 SET_RANDOM_COLOR
541 this->drawSimpleRect(bounds, 0, NULL);
542 }
543 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000544 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000545 fClip = clip;
546 // recusive draws would have disabled this.
547 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000548 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000549
reed@google.comac10a2d2010-12-22 21:39:39 +0000550 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000551 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000552
reed@google.comac10a2d2010-12-22 21:39:39 +0000553 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000554 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000555 return false;
556 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000557 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000558 return true;
559}
560
reed@google.com07f3ee12011-05-16 17:21:57 +0000561GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000562 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000563 if (NULL != fClientPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000564 fClientPathRenderer->canDrawPath(this, path, fill)) {
565 return fClientPathRenderer;
566 } else {
567 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000568 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000569 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
570 this->supportsStencilWrapOps());
571 }
572 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
573 return fDefaultPathRenderer;
574 }
575}
576
577
bsalomon@google.comd302f142011-03-03 13:54:13 +0000578////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000579
bsalomon@google.comffca4002011-02-22 20:34:01 +0000580void GrGpu::drawIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000581 int startVertex,
582 int startIndex,
583 int vertexCount,
584 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000585 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
586 fReservedGeometry.fLocked);
587 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
588 fReservedGeometry.fLocked);
589
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000590 this->handleDirtyContext();
591
592 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000593 return;
594 }
595
596#if GR_COLLECT_STATS
597 fStats.fVertexCnt += vertexCount;
598 fStats.fIndexCnt += indexCount;
599 fStats.fDrawCnt += 1;
600#endif
601
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000602 int sVertex = startVertex;
603 int sIndex = startIndex;
604 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000605
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000606 this->onDrawIndexed(type, sVertex, sIndex,
607 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000608}
609
bsalomon@google.comffca4002011-02-22 20:34:01 +0000610void GrGpu::drawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000611 int startVertex,
612 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000613 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
614 fReservedGeometry.fLocked);
615
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000616 this->handleDirtyContext();
617
618 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000619 return;
620 }
621#if GR_COLLECT_STATS
622 fStats.fVertexCnt += vertexCount;
623 fStats.fDrawCnt += 1;
624#endif
625
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000626 int sVertex = startVertex;
627 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000628
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000629 this->onDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000630}
631
632void GrGpu::finalizeReservedVertices() {
633 GrAssert(NULL != fVertexPool);
634 fVertexPool->unlock();
635}
636
637void GrGpu::finalizeReservedIndices() {
638 GrAssert(NULL != fIndexPool);
639 fIndexPool->unlock();
640}
641
642void GrGpu::prepareVertexPool() {
643 if (NULL == fVertexPool) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000644 fVertexPool = new GrVertexBufferAllocPool(this, true,
645 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000646 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000647 fVertexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000648 } else if (!fVertexPoolInUse) {
649 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000650 fVertexPool->reset();
651 }
652}
653
654void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000655 if (NULL == fIndexPool) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000656 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000657 fIndexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000658 } else if (!fIndexPoolInUse) {
659 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000660 fIndexPool->reset();
661 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000662}
663
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000664bool GrGpu::onAcquireGeometry(GrVertexLayout vertexLayout,
665 void** vertices,
666 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000667 GrAssert(!fReservedGeometry.fLocked);
668 size_t reservedVertexSpace = 0;
669
670 if (fReservedGeometry.fVertexCount) {
671 GrAssert(NULL != vertices);
672
bsalomon@google.comd302f142011-03-03 13:54:13 +0000673 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000674
675 *vertices = fVertexPool->makeSpace(vertexLayout,
676 fReservedGeometry.fVertexCount,
677 &fCurrPoolVertexBuffer,
678 &fCurrPoolStartVertex);
679 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000680 return false;
681 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000682 reservedVertexSpace = VertexSize(vertexLayout) *
683 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000684 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000685 if (fReservedGeometry.fIndexCount) {
686 GrAssert(NULL != indices);
687
bsalomon@google.comd302f142011-03-03 13:54:13 +0000688 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000689
690 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
691 &fCurrPoolIndexBuffer,
692 &fCurrPoolStartIndex);
693 if (NULL == *indices) {
694 fVertexPool->putBack(reservedVertexSpace);
695 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000696 return false;
697 }
698 }
699 return true;
700}
701
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000702void GrGpu::onReleaseGeometry() {}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000703
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000704void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000705 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000706 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000707#if GR_DEBUG
708 bool success =
709#endif
710 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
711 vertexCount,
712 vertexArray,
713 &fCurrPoolVertexBuffer,
714 &fCurrPoolStartVertex);
715 GR_DEBUGASSERT(success);
716}
717
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000718void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000719 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000720 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000721#if GR_DEBUG
722 bool success =
723#endif
724 fIndexPool->appendIndices(indexCount,
725 indexArray,
726 &fCurrPoolIndexBuffer,
727 &fCurrPoolStartIndex);
728 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000729}
730
bsalomon@google.comd302f142011-03-03 13:54:13 +0000731////////////////////////////////////////////////////////////////////////////////
732
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000733const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000734 return fStats;
735}
736
737void GrGpu::resetStats() {
738 memset(&fStats, 0, sizeof(fStats));
739}
740
741void GrGpu::printStats() const {
742 if (GR_COLLECT_STATS) {
743 GrPrintf(
744 "-v-------------------------GPU STATS----------------------------v-\n"
745 "Stats collection is: %s\n"
746 "Draws: %04d, Verts: %04d, Indices: %04d\n"
747 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
748 "TexCreates: %04d, RTCreates:%04d\n"
749 "-^--------------------------------------------------------------^-\n",
750 (GR_COLLECT_STATS ? "ON" : "OFF"),
751 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
752 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
753 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
754 }
755}
756
757////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000758const GrSamplerState GrSamplerState::gClampNoFilter(
759 GrSamplerState::kClamp_WrapMode,
760 GrSamplerState::kClamp_WrapMode,
761 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000762 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000763 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000764
765
766
767