blob: 31e4d996689628364d3d55c34e87767118822dfe [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
bsalomon@google.comd302f142011-03-03 13:54:13 +000031////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000032
33size_t GrTexture::BytesPerPixel(PixelConfig config) {
34 switch (config) {
35 case kAlpha_8_PixelConfig:
36 case kIndex_8_PixelConfig:
37 return 1;
38 case kRGB_565_PixelConfig:
39 case kRGBA_4444_PixelConfig:
40 return 2;
41 case kRGBA_8888_PixelConfig:
42 case kRGBX_8888_PixelConfig:
43 return 4;
44 default:
45 return 0;
46 }
47}
48
49bool GrTexture::PixelConfigIsOpaque(PixelConfig config) {
50 switch (config) {
51 case GrTexture::kRGB_565_PixelConfig:
52 case GrTexture::kRGBX_8888_PixelConfig:
53 return true;
54 default:
55 return false;
56 }
57}
58
bsalomon@google.com080773c2011-03-15 19:09:25 +000059bool GrTexture::PixelConfigIsAlphaOnly(PixelConfig config) {
60 switch (config) {
61 case GrTexture::kAlpha_8_PixelConfig:
62 return true;
63 default:
64 return false;
65 }
66}
reed@google.comac10a2d2010-12-22 21:39:39 +000067
bsalomon@google.comd302f142011-03-03 13:54:13 +000068////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000069
70extern void gr_run_unittests();
71
bsalomon@google.com8fe72472011-03-30 21:26:44 +000072GrGpu::GrGpu()
73 : f8bitPaletteSupport(false)
74 , fCurrPoolVertexBuffer(NULL)
75 , fCurrPoolStartVertex(0)
76 , fCurrPoolIndexBuffer(NULL)
77 , fCurrPoolStartIndex(0)
78 , fVertexPool(NULL)
79 , fIndexPool(NULL)
80 , fQuadIndexBuffer(NULL)
81 , fUnitSquareVertexBuffer(NULL)
82 , fDefaultPathRenderer(NULL)
83 , fClientPathRenderer(NULL)
84 , fContextIsDirty(true)
85 , fVertexPoolInUse(false)
86 , fIndexPoolInUse(false)
87 , fResourceHead(NULL) {
reed@google.comac10a2d2010-12-22 21:39:39 +000088#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000089 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000090#endif
91 resetStats();
92}
93
94GrGpu::~GrGpu() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 releaseResources();
reed@google.comac10a2d2010-12-22 21:39:39 +000096}
97
bsalomon@google.com8fe72472011-03-30 21:26:44 +000098void GrGpu::abandonResources() {
99
100 while (NULL != fResourceHead) {
101 fResourceHead->abandon();
102 }
103
104 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
105 GrAssert(NULL == fUnitSquareVertexBuffer ||
106 !fUnitSquareVertexBuffer->isValid());
107 GrSafeSetNull(fQuadIndexBuffer);
108 GrSafeSetNull(fUnitSquareVertexBuffer);
109 delete fVertexPool;
110 fVertexPool = NULL;
111 delete fIndexPool;
112 fIndexPool = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000113}
114
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000115void GrGpu::releaseResources() {
116
117 while (NULL != fResourceHead) {
118 fResourceHead->release();
119 }
120
121 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
122 GrAssert(NULL == fUnitSquareVertexBuffer ||
123 !fUnitSquareVertexBuffer->isValid());
124 GrSafeSetNull(fQuadIndexBuffer);
125 GrSafeSetNull(fUnitSquareVertexBuffer);
126 delete fVertexPool;
127 fVertexPool = NULL;
128 delete fIndexPool;
129 fIndexPool = NULL;
130}
131
132void GrGpu::insertResource(GrResource* resource) {
133 GrAssert(NULL != resource);
134 GrAssert(this == resource->getGpu());
135 GrAssert(NULL == resource->fNext);
136 GrAssert(NULL == resource->fPrevious);
137
138 resource->fNext = fResourceHead;
139 if (NULL != fResourceHead) {
140 GrAssert(NULL == fResourceHead->fPrevious);
141 fResourceHead->fPrevious = resource;
142 }
143 fResourceHead = resource;
144}
145
146void GrGpu::removeResource(GrResource* resource) {
147 GrAssert(NULL != resource);
148 GrAssert(NULL != fResourceHead);
149
150 if (fResourceHead == resource) {
151 GrAssert(NULL == resource->fPrevious);
152 fResourceHead = resource->fNext;
153 } else {
154 GrAssert(NULL != fResourceHead);
155 resource->fPrevious->fNext = resource->fNext;
156 }
157 if (NULL != resource->fNext) {
158 resource->fNext->fPrevious = resource->fPrevious;
159 }
160 resource->fNext = NULL;
161 resource->fPrevious = NULL;
162}
163
164
reed@google.comac10a2d2010-12-22 21:39:39 +0000165void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000166#if GR_DEBUG
167 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
168#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000169}
170
bsalomon@google.comd302f142011-03-03 13:54:13 +0000171////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000172
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000173GrTexture* GrGpu::createTexture(const TextureDesc& desc,
174 const void* srcData, size_t rowBytes) {
175 this->handleDirtyContext();
176 return this->createTextureHelper(desc, srcData, rowBytes);
177}
178
179GrRenderTarget* GrGpu::createPlatformRenderTarget(intptr_t platformRenderTarget,
180 int stencilBits,
181 int width, int height) {
182 this->handleDirtyContext();
183 return this->createPlatformRenderTargetHelper(platformRenderTarget,
184 stencilBits,
185 width, height);
186}
187
188GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
189 this->handleDirtyContext();
190 return this->createRenderTargetFrom3DApiStateHelper();
191}
192
193GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
194 this->handleDirtyContext();
195 return this->createVertexBufferHelper(size, dynamic);
196}
197
198GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
199 this->handleDirtyContext();
200 return this->createIndexBufferHelper(size, dynamic);
201}
202
203void GrGpu::eraseColor(GrColor color) {
204 this->handleDirtyContext();
205 this->eraseColorHelper(color);
206}
207
208void GrGpu::forceRenderTargetFlush() {
209 this->handleDirtyContext();
210 this->forceRenderTargetFlushHelper();
211}
212
213bool GrGpu::readPixels(int left, int top, int width, int height,
214 GrTexture::PixelConfig config, void* buffer) {
215 this->handleDirtyContext();
216 return this->readPixelsHelper(left, top, width, height, config, buffer);
217}
218
219////////////////////////////////////////////////////////////////////////////////
220
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000221static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000222
reed@google.com8195f672011-01-12 18:14:28 +0000223GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000224
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000225static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000226 for (int i = 0; i < quadCount; ++i) {
227 indices[6 * i + 0] = 4 * i + 0;
228 indices[6 * i + 1] = 4 * i + 1;
229 indices[6 * i + 2] = 4 * i + 2;
230 indices[6 * i + 3] = 4 * i + 0;
231 indices[6 * i + 4] = 4 * i + 2;
232 indices[6 * i + 5] = 4 * i + 3;
233 }
234}
235
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000236const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000237 if (NULL == fQuadIndexBuffer) {
238 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
239 GrGpu* me = const_cast<GrGpu*>(this);
240 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
241 if (NULL != fQuadIndexBuffer) {
242 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
243 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000244 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000245 fQuadIndexBuffer->unlock();
246 } else {
247 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000248 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000249 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
250 fQuadIndexBuffer->unref();
251 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000252 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000253 }
254 GrFree(indices);
255 }
256 }
257 }
258
259 return fQuadIndexBuffer;
260}
261
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000262const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000263 if (NULL == fUnitSquareVertexBuffer) {
264
265 static const GrPoint DATA[] = {
266 GrPoint(0, 0),
267 GrPoint(GR_Scalar1,0),
268 GrPoint(GR_Scalar1,GR_Scalar1),
269 GrPoint(0, GR_Scalar1)
270 };
271 static const size_t SIZE = sizeof(DATA);
272
273 GrGpu* me = const_cast<GrGpu*>(this);
274 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
275 if (NULL != fUnitSquareVertexBuffer) {
276 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
277 fUnitSquareVertexBuffer->unref();
278 fUnitSquareVertexBuffer = NULL;
279 GrCrash("Can't get vertices into buffer!");
280 }
281 }
282 }
283
284 return fUnitSquareVertexBuffer;
285}
286
bsalomon@google.comd302f142011-03-03 13:54:13 +0000287////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000288
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000289void GrGpu::clipWillBeSet(const GrClip& newClip) {
290 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000291 fClipState.fClipIsDirty = true;
292 }
293}
294
bsalomon@google.comd302f142011-03-03 13:54:13 +0000295////////////////////////////////////////////////////////////////////////////////
296
297// stencil settings to use when clip is in stencil
298const GrStencilSettings GrGpu::gClipStencilSettings = {
299 kKeep_StencilOp, kKeep_StencilOp,
300 kKeep_StencilOp, kKeep_StencilOp,
301 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
302 0, 0,
303 0, 0,
304 0, 0
305};
306
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000307// mapping of clip-respecting stencil funcs to normal stencil funcs
308// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000309static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
310 {// Stencil-Clipping is DISABLED, effectively always inside the clip
311 // In the Clip Funcs
312 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
313 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
314 kLess_StencilFunc, // kLessIfInClip_StencilFunc
315 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
316 // Special in the clip func that forces user's ref to be 0.
317 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
318 // make ref 0 and do normal nequal.
319 },
320 {// Stencil-Clipping is ENABLED
321 // In the Clip Funcs
322 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
323 // eq stencil clip bit, mask
324 // out user bits.
325
326 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
327 // add stencil bit to mask and ref
328
329 kLess_StencilFunc, // kLessIfInClip_StencilFunc
330 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
331 // for both of these we can add
332 // the clip bit to the mask and
333 // ref and compare as normal
334 // Special in the clip func that forces user's ref to be 0.
335 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
336 // make ref have only the clip bit set
337 // and make comparison be less
338 // 10..0 < 1..user_bits..
339 }
340};
341
342GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
343 GrAssert(func >= 0);
344 if (func >= kBasicStencilFuncCount) {
345 GrAssert(func < kStencilFuncCount);
346 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
347 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
348 }
349 return func;
350}
351
352void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
353 bool clipInStencil,
354 unsigned int clipBit,
355 unsigned int userBits,
356 unsigned int* ref,
357 unsigned int* mask) {
358 if (func < kBasicStencilFuncCount) {
359 *mask &= userBits;
360 *ref &= userBits;
361 } else {
362 if (clipInStencil) {
363 switch (func) {
364 case kAlwaysIfInClip_StencilFunc:
365 *mask = clipBit;
366 *ref = clipBit;
367 break;
368 case kEqualIfInClip_StencilFunc:
369 case kLessIfInClip_StencilFunc:
370 case kLEqualIfInClip_StencilFunc:
371 *mask = (*mask & userBits) | clipBit;
372 *ref = (*ref & userBits) | clipBit;
373 break;
374 case kNonZeroIfInClip_StencilFunc:
375 *mask = (*mask & userBits) | clipBit;
376 *ref = clipBit;
377 break;
378 default:
379 GrCrash("Unknown stencil func");
380 }
381 } else {
382 *mask &= userBits;
383 *ref &= userBits;
384 }
385 }
386}
387
388////////////////////////////////////////////////////////////////////////////////
389
390#define VISUALIZE_COMPLEX_CLIP 0
391
392#if VISUALIZE_COMPLEX_CLIP
393 #include "GrRandom.h"
394 GrRandom gRandom;
395 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
396#else
397 #define SET_RANDOM_COLOR
398#endif
399
bsalomon@google.comffca4002011-02-22 20:34:01 +0000400bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000401 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000402 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000403
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000404 // we check this early because we need a valid
405 // render target to setup stencil clipping
406 // before even going into flushGraphicsState
407 if (NULL == fCurrDrawState.fRenderTarget) {
408 GrAssert(!"No render target bound.");
409 return false;
410 }
411
reed@google.comac10a2d2010-12-22 21:39:39 +0000412 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000413 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
414
415 GrRect bounds;
416 GrRect rtRect;
417 rtRect.setLTRB(0, 0,
418 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000419 if (fClip.hasConservativeBounds()) {
420 bounds = fClip.getConservativeBounds();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000421 bounds.intersectWith(rtRect);
422 } else {
423 bounds = rtRect;
424 }
425
426 bounds.roundOut(&clipRect);
427 if (clipRect.isEmpty()) {
428 clipRect.setLTRB(0,0,0,0);
429 }
430 r = &clipRect;
431
432 fClipState.fClipInStencil = !fClip.isRect() &&
433 !fClip.isEmpty() &&
434 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000435
436 if (fClipState.fClipInStencil &&
437 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000438 fClip != rt.fLastStencilClip)) {
439
440 rt.fLastStencilClip = fClip;
441 // we set the current clip to the bounds so that our recursive
442 // draws are scissored to them. We use the copy of the complex clip
443 // in the rt to render
444 const GrClip& clip = rt.fLastStencilClip;
445 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000446
447 AutoStateRestore asr(this);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000448 AutoInternalDrawGeomRestore aidgr(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000449
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000450 this->setViewMatrix(GrMatrix::I());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000451 this->eraseStencilClip(clipRect);
452 this->flushScissor(NULL);
453#if !VISUALIZE_COMPLEX_CLIP
454 this->enableState(kNoColorWrites_StateBit);
455#else
456 this->disableState(kNoColorWrites_StateBit);
457#endif
458 int count = clip.getElementCount();
459 int clipBit = rt.stencilBits();
460 clipBit = (1 << (clipBit-1));
461
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000462 // often we'll see the first two elements of the clip are
463 // the full rt size and another element intersected with it.
464 // We can skip the first full-size rect and save a big rect draw.
465 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000466 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000467 kRect_ClipType == clip.getElementType(0) &&
468 kIntersect_SetOp == clip.getOp(1)&&
469 clip.getRect(0).contains(bounds)) {
470 firstElement = 1;
471 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000472
bsalomon@google.comd302f142011-03-03 13:54:13 +0000473 // walk through each clip element and perform its set op
474 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000475 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000476 GrPathFill fill;
477 // enabled at bottom of loop
478 this->disableState(kModifyStencilClip_StateBit);
479
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000480 bool canRenderDirectToStencil; // can the clip element be drawn
481 // directly to the stencil buffer
482 // with a non-inverted fill rule
483 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000484 // resolve in/out status.
485
486 GrPathRenderer* pr = NULL;
487 GrPath::Iter pathIter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000488 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000489 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000490 fill = kEvenOdd_PathFill;
491 } else {
492 fill = clip.getPathFill(c);
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000493 const GrPath& path = clip.getPath(c);
494 pathIter.reset(path);
495 pr = this->getClipPathRenderer(&pathIter, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000496 canRenderDirectToStencil =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000497 !pr->requiresStencilPass(this, &pathIter,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000498 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000499 }
500
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000501 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000502 int passes;
503 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
504
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000505 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000506 // fill rule, and set operation can
507 // we render the element directly to
508 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000509 canDrawDirectToClip =
510 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000511 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000512 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000513 IsFillInverted(fill),
514 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000515
516 // draw the element to the client stencil bits if necessary
517 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000518 static const GrStencilSettings gDrawToStencil = {
519 kIncClamp_StencilOp, kIncClamp_StencilOp,
520 kIncClamp_StencilOp, kIncClamp_StencilOp,
521 kAlways_StencilFunc, kAlways_StencilFunc,
522 0xffffffff, 0xffffffff,
523 0x00000000, 0x00000000,
524 0xffffffff, 0xffffffff,
525 };
526 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000527 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000528 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000529 this->drawSimpleRect(clip.getRect(c), NULL, 0);
530 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000531 if (canRenderDirectToStencil) {
532 this->setStencil(gDrawToStencil);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000533 pr->drawPath(this, 0,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000534 &pathIter,
535 NonInvertedFill(fill),
536 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000537 } else {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000538 pr->drawPathToStencil(this, &pathIter,
539 NonInvertedFill(fill),
540 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000541 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000542 }
543 }
544
545 // now we modify the clip bit by rendering either the clip
546 // element directly or a bounding rect of the entire clip.
547 this->enableState(kModifyStencilClip_StateBit);
548 for (int p = 0; p < passes; ++p) {
549 this->setStencil(stencilSettings[p]);
550 if (canDrawDirectToClip) {
551 if (kRect_ClipType == clip.getElementType(c)) {
552 SET_RANDOM_COLOR
553 this->drawSimpleRect(clip.getRect(c), NULL, 0);
554 } else {
555 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000556 GrAssert(!IsFillInverted(fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000557 pr->drawPath(this, 0, &pathIter, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000558 }
559 } else {
560 SET_RANDOM_COLOR
561 this->drawSimpleRect(bounds, 0, NULL);
562 }
563 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000564 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000565 fClip = clip;
566 // recusive draws would have disabled this.
567 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000568 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000569
reed@google.comac10a2d2010-12-22 21:39:39 +0000570 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000571 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000572
reed@google.comac10a2d2010-12-22 21:39:39 +0000573 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000574 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000575 return false;
576 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000577 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000578 return true;
579}
580
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000581GrPathRenderer* GrGpu::getClipPathRenderer(GrPathIter* path,
582 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000583 if (NULL != fClientPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000584 fClientPathRenderer->canDrawPath(this, path, fill)) {
585 return fClientPathRenderer;
586 } else {
587 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000588 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000589 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
590 this->supportsStencilWrapOps());
591 }
592 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
593 return fDefaultPathRenderer;
594 }
595}
596
597
bsalomon@google.comd302f142011-03-03 13:54:13 +0000598////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000599
bsalomon@google.comffca4002011-02-22 20:34:01 +0000600void GrGpu::drawIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000601 int startVertex,
602 int startIndex,
603 int vertexCount,
604 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000605 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
606 fReservedGeometry.fLocked);
607 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
608 fReservedGeometry.fLocked);
609
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000610 this->handleDirtyContext();
611
612 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000613 return;
614 }
615
616#if GR_COLLECT_STATS
617 fStats.fVertexCnt += vertexCount;
618 fStats.fIndexCnt += indexCount;
619 fStats.fDrawCnt += 1;
620#endif
621
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000622 int sVertex = startVertex;
623 int sIndex = startIndex;
624 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000625
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000626 drawIndexedHelper(type, sVertex, sIndex,
reed@google.comac10a2d2010-12-22 21:39:39 +0000627 vertexCount, indexCount);
628}
629
bsalomon@google.comffca4002011-02-22 20:34:01 +0000630void GrGpu::drawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000631 int startVertex,
632 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000633 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
634 fReservedGeometry.fLocked);
635
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000636 this->handleDirtyContext();
637
638 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000639 return;
640 }
641#if GR_COLLECT_STATS
642 fStats.fVertexCnt += vertexCount;
643 fStats.fDrawCnt += 1;
644#endif
645
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000646 int sVertex = startVertex;
647 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000648
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000649 drawNonIndexedHelper(type, sVertex, vertexCount);
650}
651
652void GrGpu::finalizeReservedVertices() {
653 GrAssert(NULL != fVertexPool);
654 fVertexPool->unlock();
655}
656
657void GrGpu::finalizeReservedIndices() {
658 GrAssert(NULL != fIndexPool);
659 fIndexPool->unlock();
660}
661
662void GrGpu::prepareVertexPool() {
663 if (NULL == fVertexPool) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000664 fVertexPool = new GrVertexBufferAllocPool(this, true,
665 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000666 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000667 fVertexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000668 } else if (!fVertexPoolInUse) {
669 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000670 fVertexPool->reset();
671 }
672}
673
674void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000675 if (NULL == fIndexPool) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000676 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000677 fIndexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000678 } else if (!fIndexPoolInUse) {
679 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000680 fIndexPool->reset();
681 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000682}
683
684bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout,
685 void** vertices,
686 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000687 GrAssert(!fReservedGeometry.fLocked);
688 size_t reservedVertexSpace = 0;
689
690 if (fReservedGeometry.fVertexCount) {
691 GrAssert(NULL != vertices);
692
bsalomon@google.comd302f142011-03-03 13:54:13 +0000693 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000694
695 *vertices = fVertexPool->makeSpace(vertexLayout,
696 fReservedGeometry.fVertexCount,
697 &fCurrPoolVertexBuffer,
698 &fCurrPoolStartVertex);
699 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000700 return false;
701 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000702 reservedVertexSpace = VertexSize(vertexLayout) *
703 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000704 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000705 if (fReservedGeometry.fIndexCount) {
706 GrAssert(NULL != indices);
707
bsalomon@google.comd302f142011-03-03 13:54:13 +0000708 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000709
710 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
711 &fCurrPoolIndexBuffer,
712 &fCurrPoolStartIndex);
713 if (NULL == *indices) {
714 fVertexPool->putBack(reservedVertexSpace);
715 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000716 return false;
717 }
718 }
719 return true;
720}
721
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000722void GrGpu::releaseGeometryHelper() {}
723
724void GrGpu::setVertexSourceToArrayHelper(const void* vertexArray, int vertexCount) {
725 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
726 prepareVertexPool();
727#if GR_DEBUG
728 bool success =
729#endif
730 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
731 vertexCount,
732 vertexArray,
733 &fCurrPoolVertexBuffer,
734 &fCurrPoolStartVertex);
735 GR_DEBUGASSERT(success);
736}
737
738void GrGpu::setIndexSourceToArrayHelper(const void* indexArray, int indexCount) {
739 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
740 prepareIndexPool();
741#if GR_DEBUG
742 bool success =
743#endif
744 fIndexPool->appendIndices(indexCount,
745 indexArray,
746 &fCurrPoolIndexBuffer,
747 &fCurrPoolStartIndex);
748 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000749}
750
bsalomon@google.comd302f142011-03-03 13:54:13 +0000751////////////////////////////////////////////////////////////////////////////////
752
reed@google.comac10a2d2010-12-22 21:39:39 +0000753const GrGpu::Stats& GrGpu::getStats() const {
754 return fStats;
755}
756
757void GrGpu::resetStats() {
758 memset(&fStats, 0, sizeof(fStats));
759}
760
761void GrGpu::printStats() const {
762 if (GR_COLLECT_STATS) {
763 GrPrintf(
764 "-v-------------------------GPU STATS----------------------------v-\n"
765 "Stats collection is: %s\n"
766 "Draws: %04d, Verts: %04d, Indices: %04d\n"
767 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
768 "TexCreates: %04d, RTCreates:%04d\n"
769 "-^--------------------------------------------------------------^-\n",
770 (GR_COLLECT_STATS ? "ON" : "OFF"),
771 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
772 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
773 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
774 }
775}
776
777////////////////////////////////////////////////////////////////////////////////
778
779GrTexture::~GrTexture() {
780 // use this to set a break-point if needed
781// Gr_clz(3);
782}
783
784const GrSamplerState GrSamplerState::gClampNoFilter(
785 GrSamplerState::kClamp_WrapMode,
786 GrSamplerState::kClamp_WrapMode,
787 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000788 GrMatrix::I(),
reed@google.comac10a2d2010-12-22 21:39:39 +0000789 false);
790
791
792
793