blob: 66105dbc2f562659220dc38903379a7e19e5c71b [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();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000402 bounds.intersectWith(rtRect);
403 } else {
404 bounds = rtRect;
405 }
406
407 bounds.roundOut(&clipRect);
408 if (clipRect.isEmpty()) {
409 clipRect.setLTRB(0,0,0,0);
410 }
411 r = &clipRect;
412
413 fClipState.fClipInStencil = !fClip.isRect() &&
414 !fClip.isEmpty() &&
415 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000416
417 if (fClipState.fClipInStencil &&
418 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000419 fClip != rt.fLastStencilClip)) {
420
421 rt.fLastStencilClip = fClip;
422 // we set the current clip to the bounds so that our recursive
423 // draws are scissored to them. We use the copy of the complex clip
424 // in the rt to render
425 const GrClip& clip = rt.fLastStencilClip;
426 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000427
428 AutoStateRestore asr(this);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000429 AutoInternalDrawGeomRestore aidgr(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000430
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000431 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000432 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000433 this->flushScissor(NULL);
434#if !VISUALIZE_COMPLEX_CLIP
435 this->enableState(kNoColorWrites_StateBit);
436#else
437 this->disableState(kNoColorWrites_StateBit);
438#endif
439 int count = clip.getElementCount();
440 int clipBit = rt.stencilBits();
441 clipBit = (1 << (clipBit-1));
442
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000443 // often we'll see the first two elements of the clip are
444 // the full rt size and another element intersected with it.
445 // We can skip the first full-size rect and save a big rect draw.
446 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000447 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000448 kRect_ClipType == clip.getElementType(0) &&
449 kIntersect_SetOp == clip.getOp(1)&&
450 clip.getRect(0).contains(bounds)) {
451 firstElement = 1;
452 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000453
bsalomon@google.comd302f142011-03-03 13:54:13 +0000454 // walk through each clip element and perform its set op
455 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000456 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000457 GrPathFill fill;
458 // enabled at bottom of loop
459 this->disableState(kModifyStencilClip_StateBit);
460
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000461 bool canRenderDirectToStencil; // can the clip element be drawn
462 // directly to the stencil buffer
463 // with a non-inverted fill rule
464 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000465 // resolve in/out status.
466
467 GrPathRenderer* pr = NULL;
468 GrPath::Iter pathIter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000469 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000470 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000471 fill = kEvenOdd_PathFill;
472 } else {
473 fill = clip.getPathFill(c);
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000474 const GrPath& path = clip.getPath(c);
475 pathIter.reset(path);
476 pr = this->getClipPathRenderer(&pathIter, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000477 canRenderDirectToStencil =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000478 !pr->requiresStencilPass(this, &pathIter,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000479 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000480 }
481
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000482 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000483 int passes;
484 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
485
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000486 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000487 // fill rule, and set operation can
488 // we render the element directly to
489 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000490 canDrawDirectToClip =
491 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000492 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000493 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000494 IsFillInverted(fill),
495 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000496
497 // draw the element to the client stencil bits if necessary
498 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000499 static const GrStencilSettings gDrawToStencil = {
500 kIncClamp_StencilOp, kIncClamp_StencilOp,
501 kIncClamp_StencilOp, kIncClamp_StencilOp,
502 kAlways_StencilFunc, kAlways_StencilFunc,
503 0xffffffff, 0xffffffff,
504 0x00000000, 0x00000000,
505 0xffffffff, 0xffffffff,
506 };
507 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000508 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000509 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000510 this->drawSimpleRect(clip.getRect(c), NULL, 0);
511 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000512 if (canRenderDirectToStencil) {
513 this->setStencil(gDrawToStencil);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000514 pr->drawPath(this, 0,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000515 &pathIter,
516 NonInvertedFill(fill),
517 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000518 } else {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000519 pr->drawPathToStencil(this, &pathIter,
520 NonInvertedFill(fill),
521 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000522 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000523 }
524 }
525
526 // now we modify the clip bit by rendering either the clip
527 // element directly or a bounding rect of the entire clip.
528 this->enableState(kModifyStencilClip_StateBit);
529 for (int p = 0; p < passes; ++p) {
530 this->setStencil(stencilSettings[p]);
531 if (canDrawDirectToClip) {
532 if (kRect_ClipType == clip.getElementType(c)) {
533 SET_RANDOM_COLOR
534 this->drawSimpleRect(clip.getRect(c), NULL, 0);
535 } else {
536 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000537 GrAssert(!IsFillInverted(fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000538 pr->drawPath(this, 0, &pathIter, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000539 }
540 } else {
541 SET_RANDOM_COLOR
542 this->drawSimpleRect(bounds, 0, NULL);
543 }
544 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000545 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000546 fClip = clip;
547 // recusive draws would have disabled this.
548 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000549 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000550
reed@google.comac10a2d2010-12-22 21:39:39 +0000551 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000552 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000553
reed@google.comac10a2d2010-12-22 21:39:39 +0000554 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000555 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000556 return false;
557 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000558 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000559 return true;
560}
561
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000562GrPathRenderer* GrGpu::getClipPathRenderer(GrPathIter* path,
563 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000564 if (NULL != fClientPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000565 fClientPathRenderer->canDrawPath(this, path, fill)) {
566 return fClientPathRenderer;
567 } else {
568 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000569 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000570 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
571 this->supportsStencilWrapOps());
572 }
573 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
574 return fDefaultPathRenderer;
575 }
576}
577
578
bsalomon@google.comd302f142011-03-03 13:54:13 +0000579////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000580
bsalomon@google.comffca4002011-02-22 20:34:01 +0000581void GrGpu::drawIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000582 int startVertex,
583 int startIndex,
584 int vertexCount,
585 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000586 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
587 fReservedGeometry.fLocked);
588 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
589 fReservedGeometry.fLocked);
590
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000591 this->handleDirtyContext();
592
593 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000594 return;
595 }
596
597#if GR_COLLECT_STATS
598 fStats.fVertexCnt += vertexCount;
599 fStats.fIndexCnt += indexCount;
600 fStats.fDrawCnt += 1;
601#endif
602
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000603 int sVertex = startVertex;
604 int sIndex = startIndex;
605 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000606
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000607 this->onDrawIndexed(type, sVertex, sIndex,
608 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000609}
610
bsalomon@google.comffca4002011-02-22 20:34:01 +0000611void GrGpu::drawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000612 int startVertex,
613 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000614 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
615 fReservedGeometry.fLocked);
616
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000617 this->handleDirtyContext();
618
619 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000620 return;
621 }
622#if GR_COLLECT_STATS
623 fStats.fVertexCnt += vertexCount;
624 fStats.fDrawCnt += 1;
625#endif
626
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000627 int sVertex = startVertex;
628 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000629
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000630 this->onDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000631}
632
633void GrGpu::finalizeReservedVertices() {
634 GrAssert(NULL != fVertexPool);
635 fVertexPool->unlock();
636}
637
638void GrGpu::finalizeReservedIndices() {
639 GrAssert(NULL != fIndexPool);
640 fIndexPool->unlock();
641}
642
643void GrGpu::prepareVertexPool() {
644 if (NULL == fVertexPool) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000645 fVertexPool = new GrVertexBufferAllocPool(this, true,
646 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000647 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000648 fVertexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000649 } else if (!fVertexPoolInUse) {
650 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000651 fVertexPool->reset();
652 }
653}
654
655void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000656 if (NULL == fIndexPool) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000657 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000658 fIndexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000659 } else if (!fIndexPoolInUse) {
660 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000661 fIndexPool->reset();
662 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000663}
664
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000665bool GrGpu::onAcquireGeometry(GrVertexLayout vertexLayout,
666 void** vertices,
667 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000668 GrAssert(!fReservedGeometry.fLocked);
669 size_t reservedVertexSpace = 0;
670
671 if (fReservedGeometry.fVertexCount) {
672 GrAssert(NULL != vertices);
673
bsalomon@google.comd302f142011-03-03 13:54:13 +0000674 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000675
676 *vertices = fVertexPool->makeSpace(vertexLayout,
677 fReservedGeometry.fVertexCount,
678 &fCurrPoolVertexBuffer,
679 &fCurrPoolStartVertex);
680 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000681 return false;
682 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000683 reservedVertexSpace = VertexSize(vertexLayout) *
684 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000685 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000686 if (fReservedGeometry.fIndexCount) {
687 GrAssert(NULL != indices);
688
bsalomon@google.comd302f142011-03-03 13:54:13 +0000689 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000690
691 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
692 &fCurrPoolIndexBuffer,
693 &fCurrPoolStartIndex);
694 if (NULL == *indices) {
695 fVertexPool->putBack(reservedVertexSpace);
696 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000697 return false;
698 }
699 }
700 return true;
701}
702
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000703void GrGpu::onReleaseGeometry() {}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000704
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000705void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000706 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000707 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000708#if GR_DEBUG
709 bool success =
710#endif
711 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
712 vertexCount,
713 vertexArray,
714 &fCurrPoolVertexBuffer,
715 &fCurrPoolStartVertex);
716 GR_DEBUGASSERT(success);
717}
718
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000719void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000720 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000721 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000722#if GR_DEBUG
723 bool success =
724#endif
725 fIndexPool->appendIndices(indexCount,
726 indexArray,
727 &fCurrPoolIndexBuffer,
728 &fCurrPoolStartIndex);
729 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000730}
731
bsalomon@google.comd302f142011-03-03 13:54:13 +0000732////////////////////////////////////////////////////////////////////////////////
733
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000734const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000735 return fStats;
736}
737
738void GrGpu::resetStats() {
739 memset(&fStats, 0, sizeof(fStats));
740}
741
742void GrGpu::printStats() const {
743 if (GR_COLLECT_STATS) {
744 GrPrintf(
745 "-v-------------------------GPU STATS----------------------------v-\n"
746 "Stats collection is: %s\n"
747 "Draws: %04d, Verts: %04d, Indices: %04d\n"
748 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
749 "TexCreates: %04d, RTCreates:%04d\n"
750 "-^--------------------------------------------------------------^-\n",
751 (GR_COLLECT_STATS ? "ON" : "OFF"),
752 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
753 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
754 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
755 }
756}
757
758////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000759const GrSamplerState GrSamplerState::gClampNoFilter(
760 GrSamplerState::kClamp_WrapMode,
761 GrSamplerState::kClamp_WrapMode,
762 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000763 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000764 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000765
766
767
768