blob: 53b5c03c97aa1fbb56fc624b33cf81ada4a45c7b [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@google.comac10a2d2010-12-22 21:39:39 +000010#include "GrGpu.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000011
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +000012#include "GrBufferAllocPool.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000013#include "GrClipIterator.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000014#include "GrContext.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000015#include "GrIndexBuffer.h"
bsalomon@google.com4043ae22011-08-02 14:19:11 +000016#include "GrPathRenderer.h"
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +000017#include "GrGLStencilBuffer.h"
18#include "GrVertexBuffer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000019
20// probably makes no sense for this to be less than a page
bsalomon@google.comee435122011-07-01 14:57:55 +000021static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
22static const int VERTEX_POOL_VB_COUNT = 4;
bsalomon@google.com25fd36c2011-07-06 17:41:08 +000023static const size_t INDEX_POOL_IB_SIZE = 1 << 16;
24static const int INDEX_POOL_IB_COUNT = 4;
reed@google.comac10a2d2010-12-22 21:39:39 +000025
bsalomon@google.comd302f142011-03-03 13:54:13 +000026////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +000027
28extern void gr_run_unittests();
29
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000030#define DEBUG_INVAL_BUFFER 0xdeadcafe
31#define DEBUG_INVAL_START_IDX -1
32
bsalomon@google.com8fe72472011-03-30 21:26:44 +000033GrGpu::GrGpu()
34 : f8bitPaletteSupport(false)
bsalomon@google.com669fdc42011-04-05 17:08:27 +000035 , fContext(NULL)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000036 , fVertexPool(NULL)
37 , fIndexPool(NULL)
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000038 , fVertexPoolUseCnt(0)
39 , fIndexPoolUseCnt(0)
40 , fGeomPoolStateStack(&fGeoSrcStateStackStorage)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000041 , fQuadIndexBuffer(NULL)
42 , fUnitSquareVertexBuffer(NULL)
43 , fDefaultPathRenderer(NULL)
44 , fClientPathRenderer(NULL)
45 , fContextIsDirty(true)
bsalomon@google.com8fe72472011-03-30 21:26:44 +000046 , fResourceHead(NULL) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +000047
reed@google.comac10a2d2010-12-22 21:39:39 +000048#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000049 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000050#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +000051
52 fGeomPoolStateStack.push_back();
53#if GR_DEBUG
54 GeometryPoolState& poolState = fGeomPoolStateStack.back();
55 poolState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
56 poolState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
57 poolState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
58 poolState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
59#endif
reed@google.comac10a2d2010-12-22 21:39:39 +000060 resetStats();
61}
62
63GrGpu::~GrGpu() {
bsalomon@google.com558a75b2011-08-08 17:01:14 +000064 this->releaseResources();
reed@google.comac10a2d2010-12-22 21:39:39 +000065}
66
bsalomon@google.com8fe72472011-03-30 21:26:44 +000067void GrGpu::abandonResources() {
68
69 while (NULL != fResourceHead) {
70 fResourceHead->abandon();
71 }
72
73 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
74 GrAssert(NULL == fUnitSquareVertexBuffer ||
75 !fUnitSquareVertexBuffer->isValid());
76 GrSafeSetNull(fQuadIndexBuffer);
77 GrSafeSetNull(fUnitSquareVertexBuffer);
78 delete fVertexPool;
79 fVertexPool = NULL;
80 delete fIndexPool;
81 fIndexPool = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +000082}
83
bsalomon@google.com8fe72472011-03-30 21:26:44 +000084void GrGpu::releaseResources() {
85
86 while (NULL != fResourceHead) {
87 fResourceHead->release();
88 }
89
90 GrAssert(NULL == fQuadIndexBuffer || !fQuadIndexBuffer->isValid());
91 GrAssert(NULL == fUnitSquareVertexBuffer ||
92 !fUnitSquareVertexBuffer->isValid());
93 GrSafeSetNull(fQuadIndexBuffer);
94 GrSafeSetNull(fUnitSquareVertexBuffer);
95 delete fVertexPool;
96 fVertexPool = NULL;
97 delete fIndexPool;
98 fIndexPool = NULL;
99}
100
101void GrGpu::insertResource(GrResource* resource) {
102 GrAssert(NULL != resource);
103 GrAssert(this == resource->getGpu());
104 GrAssert(NULL == resource->fNext);
105 GrAssert(NULL == resource->fPrevious);
106
107 resource->fNext = fResourceHead;
108 if (NULL != fResourceHead) {
109 GrAssert(NULL == fResourceHead->fPrevious);
110 fResourceHead->fPrevious = resource;
111 }
112 fResourceHead = resource;
113}
114
115void GrGpu::removeResource(GrResource* resource) {
116 GrAssert(NULL != resource);
117 GrAssert(NULL != fResourceHead);
118
119 if (fResourceHead == resource) {
120 GrAssert(NULL == resource->fPrevious);
121 fResourceHead = resource->fNext;
122 } else {
123 GrAssert(NULL != fResourceHead);
124 resource->fPrevious->fNext = resource->fNext;
125 }
126 if (NULL != resource->fNext) {
127 resource->fNext->fPrevious = resource->fPrevious;
128 }
129 resource->fNext = NULL;
130 resource->fPrevious = NULL;
131}
132
133
reed@google.comac10a2d2010-12-22 21:39:39 +0000134void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000135#if GR_DEBUG
136 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
137#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000138}
139
bsalomon@google.comd302f142011-03-03 13:54:13 +0000140////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000141
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000142GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000143 const void* srcData, size_t rowBytes) {
144 this->handleDirtyContext();
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000145 GrTexture* tex = this->onCreateTexture(desc, srcData, rowBytes);
146 if (NULL != tex &&
147 (kRenderTarget_GrTextureFlagBit & desc.fFlags) &&
148 !(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
149 GrAssert(NULL != tex->asRenderTarget());
150 // TODO: defer this and attach dynamically
151 if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) {
152 tex->unref();
153 return NULL;
154 }
155 }
156 return tex;
157}
158
159bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000160 GrAssert(NULL == rt->getStencilBuffer());
161 GrStencilBuffer* sb =
162 this->getContext()->findStencilBuffer(rt->allocatedWidth(),
163 rt->allocatedHeight(),
164 rt->numSamples());
165 if (NULL != sb) {
166 rt->setStencilBuffer(sb);
167 bool attached = this->attachStencilBufferToRenderTarget(sb, rt);
168 if (!attached) {
169 rt->setStencilBuffer(NULL);
170 }
171 return attached;
172 }
173 if (this->createStencilBufferForRenderTarget(rt, rt->allocatedWidth(),
174 rt->allocatedHeight())) {
175 rt->getStencilBuffer()->ref();
176 rt->getStencilBuffer()->transferToCacheAndLock();
177
bsalomon@google.comedc177d2011-08-05 15:46:40 +0000178 // Right now we're clearing the stencil buffer here after it is
179 // attached to an RT for the first time. When we start matching
180 // stencil buffers with smaller color targets this will no longer
181 // be correct because it won't be guaranteed to clear the entire
182 // sb.
183 // We used to clear down in the GL subclass using a special purpose
184 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
185 // FBO status.
186 GrRenderTarget* oldRT = fCurrDrawState.fRenderTarget;
187 fCurrDrawState.fRenderTarget = rt;
188 this->clearStencil();
189 fCurrDrawState.fRenderTarget = oldRT;
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000190 return true;
191 } else {
192 return false;
bsalomon@google.comedc177d2011-08-05 15:46:40 +0000193 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000194}
195
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000196GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
197 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000198 return this->onCreateRenderTargetFrom3DApiState();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000199}
200
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000201GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
202 this->handleDirtyContext();
203 return this->onCreatePlatformSurface(desc);
204}
205
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000206GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
207 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000208 return this->onCreateVertexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000209}
210
211GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
212 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000213 return this->onCreateIndexBuffer(size, dynamic);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000214}
215
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000216void GrGpu::clear(const GrIRect* rect, GrColor color) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000217 this->handleDirtyContext();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000218 this->onClear(rect, color);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000219}
220
221void GrGpu::forceRenderTargetFlush() {
222 this->handleDirtyContext();
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000223 this->onForceRenderTargetFlush();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000224}
225
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000226bool GrGpu::readPixels(GrRenderTarget* target,
227 int left, int top, int width, int height,
228 GrPixelConfig config, void* buffer) {
229
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000230 this->handleDirtyContext();
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000231 return this->onReadPixels(target, left, top, width, height, config, buffer);
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000232}
233
234////////////////////////////////////////////////////////////////////////////////
235
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000236static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000237
reed@google.com8195f672011-01-12 18:14:28 +0000238GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000239
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000240static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000241 for (int i = 0; i < quadCount; ++i) {
242 indices[6 * i + 0] = 4 * i + 0;
243 indices[6 * i + 1] = 4 * i + 1;
244 indices[6 * i + 2] = 4 * i + 2;
245 indices[6 * i + 3] = 4 * i + 0;
246 indices[6 * i + 4] = 4 * i + 2;
247 indices[6 * i + 5] = 4 * i + 3;
248 }
249}
250
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000251const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000252 if (NULL == fQuadIndexBuffer) {
253 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
254 GrGpu* me = const_cast<GrGpu*>(this);
255 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
256 if (NULL != fQuadIndexBuffer) {
257 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
258 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000259 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000260 fQuadIndexBuffer->unlock();
261 } else {
262 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000263 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000264 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
265 fQuadIndexBuffer->unref();
266 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000267 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000268 }
269 GrFree(indices);
270 }
271 }
272 }
273
274 return fQuadIndexBuffer;
275}
276
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000277const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000278 if (NULL == fUnitSquareVertexBuffer) {
279
280 static const GrPoint DATA[] = {
reed@google.com7744c202011-05-06 19:26:26 +0000281 { 0, 0 },
282 { GR_Scalar1, 0 },
283 { GR_Scalar1, GR_Scalar1 },
284 { 0, GR_Scalar1 }
285#if 0
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000286 GrPoint(0, 0),
287 GrPoint(GR_Scalar1,0),
288 GrPoint(GR_Scalar1,GR_Scalar1),
289 GrPoint(0, GR_Scalar1)
reed@google.com7744c202011-05-06 19:26:26 +0000290#endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000291 };
292 static const size_t SIZE = sizeof(DATA);
293
294 GrGpu* me = const_cast<GrGpu*>(this);
295 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
296 if (NULL != fUnitSquareVertexBuffer) {
297 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
298 fUnitSquareVertexBuffer->unref();
299 fUnitSquareVertexBuffer = NULL;
300 GrCrash("Can't get vertices into buffer!");
301 }
302 }
303 }
304
305 return fUnitSquareVertexBuffer;
306}
307
bsalomon@google.comd302f142011-03-03 13:54:13 +0000308////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000309
bsalomon@google.comd302f142011-03-03 13:54:13 +0000310// stencil settings to use when clip is in stencil
311const GrStencilSettings GrGpu::gClipStencilSettings = {
312 kKeep_StencilOp, kKeep_StencilOp,
313 kKeep_StencilOp, kKeep_StencilOp,
314 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
315 0, 0,
316 0, 0,
317 0, 0
318};
319
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000320// mapping of clip-respecting stencil funcs to normal stencil funcs
321// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000322static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
323 {// Stencil-Clipping is DISABLED, effectively always inside the clip
324 // In the Clip Funcs
325 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
326 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
327 kLess_StencilFunc, // kLessIfInClip_StencilFunc
328 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
329 // Special in the clip func that forces user's ref to be 0.
330 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
331 // make ref 0 and do normal nequal.
332 },
333 {// Stencil-Clipping is ENABLED
334 // In the Clip Funcs
335 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
336 // eq stencil clip bit, mask
337 // out user bits.
338
339 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
340 // add stencil bit to mask and ref
341
342 kLess_StencilFunc, // kLessIfInClip_StencilFunc
343 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
344 // for both of these we can add
345 // the clip bit to the mask and
346 // ref and compare as normal
347 // Special in the clip func that forces user's ref to be 0.
348 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
349 // make ref have only the clip bit set
350 // and make comparison be less
351 // 10..0 < 1..user_bits..
352 }
353};
354
355GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
356 GrAssert(func >= 0);
357 if (func >= kBasicStencilFuncCount) {
358 GrAssert(func < kStencilFuncCount);
359 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
360 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
361 }
362 return func;
363}
364
365void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
366 bool clipInStencil,
367 unsigned int clipBit,
368 unsigned int userBits,
369 unsigned int* ref,
370 unsigned int* mask) {
371 if (func < kBasicStencilFuncCount) {
372 *mask &= userBits;
373 *ref &= userBits;
374 } else {
375 if (clipInStencil) {
376 switch (func) {
377 case kAlwaysIfInClip_StencilFunc:
378 *mask = clipBit;
379 *ref = clipBit;
380 break;
381 case kEqualIfInClip_StencilFunc:
382 case kLessIfInClip_StencilFunc:
383 case kLEqualIfInClip_StencilFunc:
384 *mask = (*mask & userBits) | clipBit;
385 *ref = (*ref & userBits) | clipBit;
386 break;
387 case kNonZeroIfInClip_StencilFunc:
388 *mask = (*mask & userBits) | clipBit;
389 *ref = clipBit;
390 break;
391 default:
392 GrCrash("Unknown stencil func");
393 }
394 } else {
395 *mask &= userBits;
396 *ref &= userBits;
397 }
398 }
399}
400
401////////////////////////////////////////////////////////////////////////////////
402
403#define VISUALIZE_COMPLEX_CLIP 0
404
405#if VISUALIZE_COMPLEX_CLIP
406 #include "GrRandom.h"
407 GrRandom gRandom;
408 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
409#else
410 #define SET_RANDOM_COLOR
411#endif
412
bsalomon@google.comffca4002011-02-22 20:34:01 +0000413bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000414 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000415 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000416
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000417 // we check this early because we need a valid
418 // render target to setup stencil clipping
419 // before even going into flushGraphicsState
420 if (NULL == fCurrDrawState.fRenderTarget) {
421 GrAssert(!"No render target bound.");
422 return false;
423 }
424
reed@google.comac10a2d2010-12-22 21:39:39 +0000425 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000426 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
427
428 GrRect bounds;
429 GrRect rtRect;
430 rtRect.setLTRB(0, 0,
431 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000432 if (fClip.hasConservativeBounds()) {
433 bounds = fClip.getConservativeBounds();
reed@google.com20efde72011-05-09 17:00:02 +0000434 if (!bounds.intersect(rtRect)) {
435 bounds.setEmpty();
436 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000437 } else {
438 bounds = rtRect;
439 }
440
441 bounds.roundOut(&clipRect);
442 if (clipRect.isEmpty()) {
443 clipRect.setLTRB(0,0,0,0);
444 }
445 r = &clipRect;
446
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000447 // use the stencil clip if we can't represent the clip as a rectangle.
448 fClipInStencil = !fClip.isRect() && !fClip.isEmpty() &&
449 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000450
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000451 // TODO: dynamically attach a SB when needed.
452 GrStencilBuffer* stencilBuffer = rt.getStencilBuffer();
453 if (fClipInStencil && NULL == stencilBuffer) {
454 return false;
455 }
bsalomon@google.coma16d6502011-08-02 14:07:52 +0000456
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000457 if (fClipInStencil &&
458 stencilBuffer->mustRenderClip(fClip, rt.width(), rt.height())) {
459
460 stencilBuffer->setLastClip(fClip, rt.width(), rt.height());
461
bsalomon@google.comd302f142011-03-03 13:54:13 +0000462 // we set the current clip to the bounds so that our recursive
463 // draws are scissored to them. We use the copy of the complex clip
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000464 // we just stashed on the SB to render from. We set it back after
465 // we finish drawing it into the stencil.
466 const GrClip& clip = stencilBuffer->getLastClip();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000467 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000468
469 AutoStateRestore asr(this);
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000470 AutoGeometryPush agp(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000471
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000472 this->setViewMatrix(GrMatrix::I());
bsalomon@google.com398109c2011-04-14 18:40:27 +0000473 this->clearStencilClip(clipRect);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000474 this->flushScissor(NULL);
475#if !VISUALIZE_COMPLEX_CLIP
476 this->enableState(kNoColorWrites_StateBit);
477#else
478 this->disableState(kNoColorWrites_StateBit);
479#endif
480 int count = clip.getElementCount();
bsalomon@google.com81c3f8d2011-08-03 15:18:33 +0000481 int clipBit = stencilBuffer->bits();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000482 clipBit = (1 << (clipBit-1));
483
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000484 // often we'll see the first two elements of the clip are
485 // the full rt size and another element intersected with it.
486 // We can skip the first full-size rect and save a big rect draw.
487 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000488 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000489 kRect_ClipType == clip.getElementType(0) &&
490 kIntersect_SetOp == clip.getOp(1)&&
491 clip.getRect(0).contains(bounds)) {
492 firstElement = 1;
493 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000494
bsalomon@google.comd302f142011-03-03 13:54:13 +0000495 // walk through each clip element and perform its set op
496 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000497 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000498 GrPathFill fill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000499 bool fillInverted;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000500 // enabled at bottom of loop
501 this->disableState(kModifyStencilClip_StateBit);
502
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000503 bool canRenderDirectToStencil; // can the clip element be drawn
504 // directly to the stencil buffer
505 // with a non-inverted fill rule
506 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000507 // resolve in/out status.
508
509 GrPathRenderer* pr = NULL;
reed@google.com07f3ee12011-05-16 17:21:57 +0000510 const GrPath* clipPath = NULL;
bsalomon@google.comee435122011-07-01 14:57:55 +0000511 GrPathRenderer::AutoClearPath arp;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000512 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000513 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000514 fill = kEvenOdd_PathFill;
bsalomon@google.comee435122011-07-01 14:57:55 +0000515 fillInverted = false;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000516 } else {
517 fill = clip.getPathFill(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000518 fillInverted = IsFillInverted(fill);
519 fill = NonInvertedFill(fill);
reed@google.com07f3ee12011-05-16 17:21:57 +0000520 clipPath = &clip.getPath(c);
bsalomon@google.comee435122011-07-01 14:57:55 +0000521 pr = this->getClipPathRenderer(*clipPath, fill);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000522 canRenderDirectToStencil =
bsalomon@google.comee435122011-07-01 14:57:55 +0000523 !pr->requiresStencilPass(this, *clipPath, fill);
524 arp.set(pr, this, clipPath, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000525 }
526
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000527 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000528 int passes;
529 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
530
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000531 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000532 // fill rule, and set operation can
533 // we render the element directly to
534 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000535 canDrawDirectToClip =
536 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000537 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000538 clipBit,
bsalomon@google.comee435122011-07-01 14:57:55 +0000539 fillInverted,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000540 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000541
542 // draw the element to the client stencil bits if necessary
543 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000544 static const GrStencilSettings gDrawToStencil = {
545 kIncClamp_StencilOp, kIncClamp_StencilOp,
546 kIncClamp_StencilOp, kIncClamp_StencilOp,
547 kAlways_StencilFunc, kAlways_StencilFunc,
548 0xffffffff, 0xffffffff,
549 0x00000000, 0x00000000,
550 0xffffffff, 0xffffffff,
551 };
552 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000553 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000554 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000555 this->drawSimpleRect(clip.getRect(c), NULL, 0);
556 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000557 if (canRenderDirectToStencil) {
558 this->setStencil(gDrawToStencil);
bsalomon@google.comee435122011-07-01 14:57:55 +0000559 pr->drawPath(0);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000560 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000561 pr->drawPathToStencil();
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000562 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000563 }
564 }
565
566 // now we modify the clip bit by rendering either the clip
567 // element directly or a bounding rect of the entire clip.
568 this->enableState(kModifyStencilClip_StateBit);
569 for (int p = 0; p < passes; ++p) {
570 this->setStencil(stencilSettings[p]);
571 if (canDrawDirectToClip) {
572 if (kRect_ClipType == clip.getElementType(c)) {
573 SET_RANDOM_COLOR
574 this->drawSimpleRect(clip.getRect(c), NULL, 0);
575 } else {
576 SET_RANDOM_COLOR
bsalomon@google.comee435122011-07-01 14:57:55 +0000577 pr->drawPath(0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000578 }
579 } else {
580 SET_RANDOM_COLOR
thakis@chromium.org441d7da2011-06-07 04:03:17 +0000581 this->drawSimpleRect(bounds, NULL, 0);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000582 }
583 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000584 }
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000585 // restore clip
bsalomon@google.comd302f142011-03-03 13:54:13 +0000586 fClip = clip;
bsalomon@google.comdea2f8d2011-08-01 15:51:05 +0000587 // recusive draws would have disabled this since they drew with
588 // the clip bounds as clip.
589 fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000590 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000591 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000592
reed@google.comac10a2d2010-12-22 21:39:39 +0000593 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000594 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000595 return false;
596 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000597 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000598 return true;
599}
600
reed@google.com07f3ee12011-05-16 17:21:57 +0000601GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000602 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000603 if (NULL != fClientPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +0000604 fClientPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000605 return fClientPathRenderer;
606 } else {
607 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000608 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000609 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
610 this->supportsStencilWrapOps());
611 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000612 GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000613 return fDefaultPathRenderer;
614 }
615}
616
617
bsalomon@google.comd302f142011-03-03 13:54:13 +0000618////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000619
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000620void GrGpu::geometrySourceWillPush() {
621 const GeometrySrcState& geoSrc = this->getGeomSrc();
622 if (kArray_GeometrySrcType == geoSrc.fVertexSrc ||
623 kReserved_GeometrySrcType == geoSrc.fVertexSrc) {
624 this->finalizeReservedVertices();
625 }
626 if (kArray_GeometrySrcType == geoSrc.fIndexSrc ||
627 kReserved_GeometrySrcType == geoSrc.fIndexSrc) {
628 this->finalizeReservedIndices();
629 }
630 GeometryPoolState& newState = fGeomPoolStateStack.push_back();
631#if GR_DEBUG
632 newState.fPoolVertexBuffer = (GrVertexBuffer*)DEBUG_INVAL_BUFFER;
633 newState.fPoolStartVertex = DEBUG_INVAL_START_IDX;
634 newState.fPoolIndexBuffer = (GrIndexBuffer*)DEBUG_INVAL_BUFFER;
635 newState.fPoolStartIndex = DEBUG_INVAL_START_IDX;
636#endif
637}
638
639void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) {
640 // if popping last entry then pops are unbalanced with pushes
641 GrAssert(fGeomPoolStateStack.count() > 1);
642 fGeomPoolStateStack.pop_back();
643}
644
645void GrGpu::onDrawIndexed(GrPrimitiveType type,
646 int startVertex,
647 int startIndex,
648 int vertexCount,
649 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000650
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000651 this->handleDirtyContext();
652
653 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000654 return;
655 }
656
657#if GR_COLLECT_STATS
658 fStats.fVertexCnt += vertexCount;
659 fStats.fIndexCnt += indexCount;
660 fStats.fDrawCnt += 1;
661#endif
662
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000663 int sVertex = startVertex;
664 int sIndex = startIndex;
665 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000666
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000667 this->onGpuDrawIndexed(type, sVertex, sIndex,
668 vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000669}
670
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000671void GrGpu::onDrawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000672 int startVertex,
673 int vertexCount) {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000674 this->handleDirtyContext();
675
676 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000677 return;
678 }
679#if GR_COLLECT_STATS
680 fStats.fVertexCnt += vertexCount;
681 fStats.fDrawCnt += 1;
682#endif
683
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000684 int sVertex = startVertex;
685 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000686
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000687 this->onGpuDrawNonIndexed(type, sVertex, vertexCount);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000688}
689
690void GrGpu::finalizeReservedVertices() {
691 GrAssert(NULL != fVertexPool);
692 fVertexPool->unlock();
693}
694
695void GrGpu::finalizeReservedIndices() {
696 GrAssert(NULL != fIndexPool);
697 fIndexPool->unlock();
698}
699
700void GrGpu::prepareVertexPool() {
701 if (NULL == fVertexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000702 GrAssert(0 == fVertexPoolUseCnt);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000703 fVertexPool = new GrVertexBufferAllocPool(this, true,
704 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000705 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000706 fVertexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000707 } else if (!fVertexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000708 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000709 fVertexPool->reset();
710 }
711}
712
713void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000714 if (NULL == fIndexPool) {
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000715 GrAssert(0 == fIndexPoolUseCnt);
bsalomon@google.com25fd36c2011-07-06 17:41:08 +0000716 fIndexPool = new GrIndexBufferAllocPool(this, true,
717 INDEX_POOL_IB_SIZE,
718 INDEX_POOL_IB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000719 fIndexPool->releaseGpuRef();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000720 } else if (!fIndexPoolUseCnt) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000721 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000722 fIndexPool->reset();
723 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000724}
725
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000726bool GrGpu::onReserveVertexSpace(GrVertexLayout vertexLayout,
727 int vertexCount,
728 void** vertices) {
729 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
730
731 GrAssert(vertexCount > 0);
732 GrAssert(NULL != vertices);
733
734 this->prepareVertexPool();
735
736 *vertices = fVertexPool->makeSpace(vertexLayout,
737 vertexCount,
738 &geomPoolState.fPoolVertexBuffer,
739 &geomPoolState.fPoolStartVertex);
740 if (NULL == *vertices) {
741 return false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000742 }
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000743 ++fVertexPoolUseCnt;
reed@google.comac10a2d2010-12-22 21:39:39 +0000744 return true;
745}
746
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000747bool GrGpu::onReserveIndexSpace(int indexCount, void** indices) {
748 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
749
750 GrAssert(indexCount > 0);
751 GrAssert(NULL != indices);
752
753 this->prepareIndexPool();
754
755 *indices = fIndexPool->makeSpace(indexCount,
756 &geomPoolState.fPoolIndexBuffer,
757 &geomPoolState.fPoolStartIndex);
758 if (NULL == *indices) {
759 return false;
760 }
761 ++fIndexPoolUseCnt;
762 return true;
763}
764
765void GrGpu::releaseReservedVertexSpace() {
766 const GeometrySrcState& geoSrc = this->getGeomSrc();
767 GrAssert(kReserved_GeometrySrcType == geoSrc.fVertexSrc);
768 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
769 fVertexPool->putBack(bytes);
770 --fVertexPoolUseCnt;
771}
772
773void GrGpu::releaseReservedIndexSpace() {
774 const GeometrySrcState& geoSrc = this->getGeomSrc();
775 GrAssert(kReserved_GeometrySrcType == geoSrc.fIndexSrc);
776 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
777 fIndexPool->putBack(bytes);
778 --fIndexPoolUseCnt;
779}
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000780
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000781void GrGpu::onSetVertexSourceToArray(const void* vertexArray, int vertexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000782 this->prepareVertexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000783 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000784#if GR_DEBUG
785 bool success =
786#endif
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000787 fVertexPool->appendVertices(this->getGeomSrc().fVertexLayout,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000788 vertexCount,
789 vertexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000790 &geomPoolState.fPoolVertexBuffer,
791 &geomPoolState.fPoolStartVertex);
792 ++fVertexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000793 GR_DEBUGASSERT(success);
794}
795
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000796void GrGpu::onSetIndexSourceToArray(const void* indexArray, int indexCount) {
bsalomon@google.combcdbbe62011-04-12 15:40:00 +0000797 this->prepareIndexPool();
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000798 GeometryPoolState& geomPoolState = fGeomPoolStateStack.back();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000799#if GR_DEBUG
800 bool success =
801#endif
802 fIndexPool->appendIndices(indexCount,
803 indexArray,
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000804 &geomPoolState.fPoolIndexBuffer,
805 &geomPoolState.fPoolStartIndex);
806 ++fIndexPoolUseCnt;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000807 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000808}
809
bsalomon@google.com25fb21f2011-06-21 18:17:25 +0000810void GrGpu::releaseVertexArray() {
811 // if vertex source was array, we stowed data in the pool
812 const GeometrySrcState& geoSrc = this->getGeomSrc();
813 GrAssert(kArray_GeometrySrcType == geoSrc.fVertexSrc);
814 size_t bytes = geoSrc.fVertexCount * VertexSize(geoSrc.fVertexLayout);
815 fVertexPool->putBack(bytes);
816 --fVertexPoolUseCnt;
817}
818
819void GrGpu::releaseIndexArray() {
820 // if index source was array, we stowed data in the pool
821 const GeometrySrcState& geoSrc = this->getGeomSrc();
822 GrAssert(kArray_GeometrySrcType == geoSrc.fIndexSrc);
823 size_t bytes = geoSrc.fIndexCount * sizeof(uint16_t);
824 fIndexPool->putBack(bytes);
825 --fIndexPoolUseCnt;
826}
827
bsalomon@google.comd302f142011-03-03 13:54:13 +0000828////////////////////////////////////////////////////////////////////////////////
829
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000830const GrGpuStats& GrGpu::getStats() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000831 return fStats;
832}
833
834void GrGpu::resetStats() {
835 memset(&fStats, 0, sizeof(fStats));
836}
837
838void GrGpu::printStats() const {
839 if (GR_COLLECT_STATS) {
840 GrPrintf(
841 "-v-------------------------GPU STATS----------------------------v-\n"
842 "Stats collection is: %s\n"
843 "Draws: %04d, Verts: %04d, Indices: %04d\n"
844 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
845 "TexCreates: %04d, RTCreates:%04d\n"
846 "-^--------------------------------------------------------------^-\n",
847 (GR_COLLECT_STATS ? "ON" : "OFF"),
848 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
849 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
850 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
851 }
852}
853
854////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000855const GrSamplerState GrSamplerState::gClampNoFilter(
856 GrSamplerState::kClamp_WrapMode,
857 GrSamplerState::kClamp_WrapMode,
858 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000859 GrMatrix::I(),
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000860 GrSamplerState::kNearest_Filter);
reed@google.comac10a2d2010-12-22 21:39:39 +0000861
862
863
864