blob: 378b8816370fcd286710bde90749d85748e15796 [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
72GrGpu::GrGpu() : f8bitPaletteSupport(false),
bsalomon@google.com1c13c962011-02-14 16:51:21 +000073 fCurrPoolVertexBuffer(NULL),
74 fCurrPoolStartVertex(0),
75 fCurrPoolIndexBuffer(NULL),
76 fCurrPoolStartIndex(0),
77 fVertexPool(NULL),
78 fIndexPool(NULL),
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000079 fQuadIndexBuffer(NULL),
bsalomon@google.comd302f142011-03-03 13:54:13 +000080 fUnitSquareVertexBuffer(NULL),
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000081 fDefaultPathRenderer(NULL),
82 fClientPathRenderer(NULL),
bsalomon@google.coma7f84e12011-03-10 14:13:19 +000083 fContextIsDirty(true),
bsalomon@google.comd302f142011-03-03 13:54:13 +000084 fVertexPoolInUse(false),
85 fIndexPoolInUse(false) {
reed@google.comac10a2d2010-12-22 21:39:39 +000086#if GR_DEBUG
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +000087 //gr_run_unittests();
reed@google.comac10a2d2010-12-22 21:39:39 +000088#endif
89 resetStats();
90}
91
92GrGpu::~GrGpu() {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000093 GrSafeUnref(fQuadIndexBuffer);
94 GrSafeUnref(fUnitSquareVertexBuffer);
bsalomon@google.com1c13c962011-02-14 16:51:21 +000095 delete fVertexPool;
96 delete fIndexPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000097 GrSafeUnref(fClientPathRenderer);
98 GrSafeUnref(fDefaultPathRenderer);
reed@google.comac10a2d2010-12-22 21:39:39 +000099}
100
101void GrGpu::resetContext() {
102}
103
104void GrGpu::unimpl(const char msg[]) {
bsalomon@google.com7d34d2e2011-01-24 17:41:47 +0000105#if GR_DEBUG
106 GrPrintf("--- GrGpu unimplemented(\"%s\")\n", msg);
107#endif
reed@google.comac10a2d2010-12-22 21:39:39 +0000108}
109
bsalomon@google.comd302f142011-03-03 13:54:13 +0000110////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000111
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000112GrTexture* GrGpu::createTexture(const TextureDesc& desc,
113 const void* srcData, size_t rowBytes) {
114 this->handleDirtyContext();
115 return this->createTextureHelper(desc, srcData, rowBytes);
116}
117
118GrRenderTarget* GrGpu::createPlatformRenderTarget(intptr_t platformRenderTarget,
119 int stencilBits,
120 int width, int height) {
121 this->handleDirtyContext();
122 return this->createPlatformRenderTargetHelper(platformRenderTarget,
123 stencilBits,
124 width, height);
125}
126
127GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
128 this->handleDirtyContext();
129 return this->createRenderTargetFrom3DApiStateHelper();
130}
131
132GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
133 this->handleDirtyContext();
134 return this->createVertexBufferHelper(size, dynamic);
135}
136
137GrIndexBuffer* GrGpu::createIndexBuffer(uint32_t size, bool dynamic) {
138 this->handleDirtyContext();
139 return this->createIndexBufferHelper(size, dynamic);
140}
141
142void GrGpu::eraseColor(GrColor color) {
143 this->handleDirtyContext();
144 this->eraseColorHelper(color);
145}
146
147void GrGpu::forceRenderTargetFlush() {
148 this->handleDirtyContext();
149 this->forceRenderTargetFlushHelper();
150}
151
152bool GrGpu::readPixels(int left, int top, int width, int height,
153 GrTexture::PixelConfig config, void* buffer) {
154 this->handleDirtyContext();
155 return this->readPixelsHelper(left, top, width, height, config, buffer);
156}
157
158////////////////////////////////////////////////////////////////////////////////
159
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000160static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000161
reed@google.com8195f672011-01-12 18:14:28 +0000162GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
reed@google.comac10a2d2010-12-22 21:39:39 +0000163
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000164static inline void fill_indices(uint16_t* indices, int quadCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000165 for (int i = 0; i < quadCount; ++i) {
166 indices[6 * i + 0] = 4 * i + 0;
167 indices[6 * i + 1] = 4 * i + 1;
168 indices[6 * i + 2] = 4 * i + 2;
169 indices[6 * i + 3] = 4 * i + 0;
170 indices[6 * i + 4] = 4 * i + 2;
171 indices[6 * i + 5] = 4 * i + 3;
172 }
173}
174
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000175const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000176 if (NULL == fQuadIndexBuffer) {
177 static const int SIZE = sizeof(uint16_t) * 6 * MAX_QUADS;
178 GrGpu* me = const_cast<GrGpu*>(this);
179 fQuadIndexBuffer = me->createIndexBuffer(SIZE, false);
180 if (NULL != fQuadIndexBuffer) {
181 uint16_t* indices = (uint16_t*)fQuadIndexBuffer->lock();
182 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000183 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 fQuadIndexBuffer->unlock();
185 } else {
186 indices = (uint16_t*)GrMalloc(SIZE);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000187 fill_indices(indices, MAX_QUADS);
reed@google.comac10a2d2010-12-22 21:39:39 +0000188 if (!fQuadIndexBuffer->updateData(indices, SIZE)) {
189 fQuadIndexBuffer->unref();
190 fQuadIndexBuffer = NULL;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000191 GrCrash("Can't get indices into buffer!");
reed@google.comac10a2d2010-12-22 21:39:39 +0000192 }
193 GrFree(indices);
194 }
195 }
196 }
197
198 return fQuadIndexBuffer;
199}
200
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000201const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000202 if (NULL == fUnitSquareVertexBuffer) {
203
204 static const GrPoint DATA[] = {
205 GrPoint(0, 0),
206 GrPoint(GR_Scalar1,0),
207 GrPoint(GR_Scalar1,GR_Scalar1),
208 GrPoint(0, GR_Scalar1)
209 };
210 static const size_t SIZE = sizeof(DATA);
211
212 GrGpu* me = const_cast<GrGpu*>(this);
213 fUnitSquareVertexBuffer = me->createVertexBuffer(SIZE, false);
214 if (NULL != fUnitSquareVertexBuffer) {
215 if (!fUnitSquareVertexBuffer->updateData(DATA, SIZE)) {
216 fUnitSquareVertexBuffer->unref();
217 fUnitSquareVertexBuffer = NULL;
218 GrCrash("Can't get vertices into buffer!");
219 }
220 }
221 }
222
223 return fUnitSquareVertexBuffer;
224}
225
bsalomon@google.comd302f142011-03-03 13:54:13 +0000226////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000227
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000228void GrGpu::clipWillBeSet(const GrClip& newClip) {
229 if (newClip != fClip) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000230 fClipState.fClipIsDirty = true;
231 }
232}
233
bsalomon@google.comd302f142011-03-03 13:54:13 +0000234////////////////////////////////////////////////////////////////////////////////
235
236// stencil settings to use when clip is in stencil
237const GrStencilSettings GrGpu::gClipStencilSettings = {
238 kKeep_StencilOp, kKeep_StencilOp,
239 kKeep_StencilOp, kKeep_StencilOp,
240 kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
241 0, 0,
242 0, 0,
243 0, 0
244};
245
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000246// mapping of clip-respecting stencil funcs to normal stencil funcs
247// mapping depends on whether stencil-clipping is in effect.
bsalomon@google.comd302f142011-03-03 13:54:13 +0000248static const GrStencilFunc gGrClipToNormalStencilFunc[2][kClipStencilFuncCount] = {
249 {// Stencil-Clipping is DISABLED, effectively always inside the clip
250 // In the Clip Funcs
251 kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
252 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
253 kLess_StencilFunc, // kLessIfInClip_StencilFunc
254 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
255 // Special in the clip func that forces user's ref to be 0.
256 kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
257 // make ref 0 and do normal nequal.
258 },
259 {// Stencil-Clipping is ENABLED
260 // In the Clip Funcs
261 kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
262 // eq stencil clip bit, mask
263 // out user bits.
264
265 kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
266 // add stencil bit to mask and ref
267
268 kLess_StencilFunc, // kLessIfInClip_StencilFunc
269 kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
270 // for both of these we can add
271 // the clip bit to the mask and
272 // ref and compare as normal
273 // Special in the clip func that forces user's ref to be 0.
274 kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
275 // make ref have only the clip bit set
276 // and make comparison be less
277 // 10..0 < 1..user_bits..
278 }
279};
280
281GrStencilFunc GrGpu::ConvertStencilFunc(bool stencilInClip, GrStencilFunc func) {
282 GrAssert(func >= 0);
283 if (func >= kBasicStencilFuncCount) {
284 GrAssert(func < kStencilFuncCount);
285 func = gGrClipToNormalStencilFunc[stencilInClip ? 1 : 0][func - kBasicStencilFuncCount];
286 GrAssert(func >= 0 && func < kBasicStencilFuncCount);
287 }
288 return func;
289}
290
291void GrGpu::ConvertStencilFuncAndMask(GrStencilFunc func,
292 bool clipInStencil,
293 unsigned int clipBit,
294 unsigned int userBits,
295 unsigned int* ref,
296 unsigned int* mask) {
297 if (func < kBasicStencilFuncCount) {
298 *mask &= userBits;
299 *ref &= userBits;
300 } else {
301 if (clipInStencil) {
302 switch (func) {
303 case kAlwaysIfInClip_StencilFunc:
304 *mask = clipBit;
305 *ref = clipBit;
306 break;
307 case kEqualIfInClip_StencilFunc:
308 case kLessIfInClip_StencilFunc:
309 case kLEqualIfInClip_StencilFunc:
310 *mask = (*mask & userBits) | clipBit;
311 *ref = (*ref & userBits) | clipBit;
312 break;
313 case kNonZeroIfInClip_StencilFunc:
314 *mask = (*mask & userBits) | clipBit;
315 *ref = clipBit;
316 break;
317 default:
318 GrCrash("Unknown stencil func");
319 }
320 } else {
321 *mask &= userBits;
322 *ref &= userBits;
323 }
324 }
325}
326
327////////////////////////////////////////////////////////////////////////////////
328
329#define VISUALIZE_COMPLEX_CLIP 0
330
331#if VISUALIZE_COMPLEX_CLIP
332 #include "GrRandom.h"
333 GrRandom gRandom;
334 #define SET_RANDOM_COLOR this->setColor(0xff000000 | gRandom.nextU());
335#else
336 #define SET_RANDOM_COLOR
337#endif
338
bsalomon@google.comffca4002011-02-22 20:34:01 +0000339bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000340 const GrIRect* r = NULL;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000341 GrIRect clipRect;
reed@google.comac10a2d2010-12-22 21:39:39 +0000342
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +0000343 // we check this early because we need a valid
344 // render target to setup stencil clipping
345 // before even going into flushGraphicsState
346 if (NULL == fCurrDrawState.fRenderTarget) {
347 GrAssert(!"No render target bound.");
348 return false;
349 }
350
reed@google.comac10a2d2010-12-22 21:39:39 +0000351 if (fCurrDrawState.fFlagBits & kClip_StateBit) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000352 GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;
353
354 GrRect bounds;
355 GrRect rtRect;
356 rtRect.setLTRB(0, 0,
357 GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000358 if (fClip.hasConservativeBounds()) {
359 bounds = fClip.getConservativeBounds();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000360 bounds.intersectWith(rtRect);
361 } else {
362 bounds = rtRect;
363 }
364
365 bounds.roundOut(&clipRect);
366 if (clipRect.isEmpty()) {
367 clipRect.setLTRB(0,0,0,0);
368 }
369 r = &clipRect;
370
371 fClipState.fClipInStencil = !fClip.isRect() &&
372 !fClip.isEmpty() &&
373 !bounds.isEmpty();
reed@google.comac10a2d2010-12-22 21:39:39 +0000374
375 if (fClipState.fClipInStencil &&
376 (fClipState.fClipIsDirty ||
bsalomon@google.comd302f142011-03-03 13:54:13 +0000377 fClip != rt.fLastStencilClip)) {
378
379 rt.fLastStencilClip = fClip;
380 // we set the current clip to the bounds so that our recursive
381 // draws are scissored to them. We use the copy of the complex clip
382 // in the rt to render
383 const GrClip& clip = rt.fLastStencilClip;
384 fClip.setFromRect(bounds);
reed@google.comac10a2d2010-12-22 21:39:39 +0000385
386 AutoStateRestore asr(this);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000387 AutoInternalDrawGeomRestore aidgr(this);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000388
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000389 this->setViewMatrix(GrMatrix::I());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000390 this->eraseStencilClip(clipRect);
391 this->flushScissor(NULL);
392#if !VISUALIZE_COMPLEX_CLIP
393 this->enableState(kNoColorWrites_StateBit);
394#else
395 this->disableState(kNoColorWrites_StateBit);
396#endif
397 int count = clip.getElementCount();
398 int clipBit = rt.stencilBits();
399 clipBit = (1 << (clipBit-1));
400
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000401 // often we'll see the first two elements of the clip are
402 // the full rt size and another element intersected with it.
403 // We can skip the first full-size rect and save a big rect draw.
404 int firstElement = 0;
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000405 if (clip.getElementCount() > 1 &&
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000406 kRect_ClipType == clip.getElementType(0) &&
407 kIntersect_SetOp == clip.getOp(1)&&
408 clip.getRect(0).contains(bounds)) {
409 firstElement = 1;
410 }
bsalomon@google.com0b50b2e2011-03-08 21:07:21 +0000411
bsalomon@google.comd302f142011-03-03 13:54:13 +0000412 // walk through each clip element and perform its set op
413 // with the existing clip.
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000414 for (int c = firstElement; c < count; ++c) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000415 GrPathFill fill;
416 // enabled at bottom of loop
417 this->disableState(kModifyStencilClip_StateBit);
418
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000419 bool canRenderDirectToStencil; // can the clip element be drawn
420 // directly to the stencil buffer
421 // with a non-inverted fill rule
422 // without extra passes to
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000423 // resolve in/out status.
424
425 GrPathRenderer* pr = NULL;
426 GrPath::Iter pathIter;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000427 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000428 canRenderDirectToStencil = true;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000429 fill = kEvenOdd_PathFill;
430 } else {
431 fill = clip.getPathFill(c);
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000432 const GrPath& path = clip.getPath(c);
433 pathIter.reset(path);
434 pr = this->getClipPathRenderer(&pathIter, NonInvertedFill(fill));
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000435 canRenderDirectToStencil =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000436 !pr->requiresStencilPass(this, &pathIter,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000437 NonInvertedFill(fill));
bsalomon@google.comd302f142011-03-03 13:54:13 +0000438 }
439
bsalomon@google.com5aaa69e2011-03-04 20:29:08 +0000440 GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000441 int passes;
442 GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
443
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000444 bool canDrawDirectToClip; // Given the renderer, the element,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000445 // fill rule, and set operation can
446 // we render the element directly to
447 // stencil bit used for clipping.
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000448 canDrawDirectToClip =
449 GrStencilSettings::GetClipPasses(op,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000450 canRenderDirectToStencil,
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000451 clipBit,
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000452 IsFillInverted(fill),
453 &passes, stencilSettings);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000454
455 // draw the element to the client stencil bits if necessary
456 if (!canDrawDirectToClip) {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000457 static const GrStencilSettings gDrawToStencil = {
458 kIncClamp_StencilOp, kIncClamp_StencilOp,
459 kIncClamp_StencilOp, kIncClamp_StencilOp,
460 kAlways_StencilFunc, kAlways_StencilFunc,
461 0xffffffff, 0xffffffff,
462 0x00000000, 0x00000000,
463 0xffffffff, 0xffffffff,
464 };
465 SET_RANDOM_COLOR
bsalomon@google.comd302f142011-03-03 13:54:13 +0000466 if (kRect_ClipType == clip.getElementType(c)) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000467 this->setStencil(gDrawToStencil);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000468 this->drawSimpleRect(clip.getRect(c), NULL, 0);
469 } else {
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000470 if (canRenderDirectToStencil) {
471 this->setStencil(gDrawToStencil);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000472 pr->drawPath(this, 0,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000473 &pathIter,
474 NonInvertedFill(fill),
475 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000476 } else {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000477 pr->drawPathToStencil(this, &pathIter,
478 NonInvertedFill(fill),
479 NULL);
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000480 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000481 }
482 }
483
484 // now we modify the clip bit by rendering either the clip
485 // element directly or a bounding rect of the entire clip.
486 this->enableState(kModifyStencilClip_StateBit);
487 for (int p = 0; p < passes; ++p) {
488 this->setStencil(stencilSettings[p]);
489 if (canDrawDirectToClip) {
490 if (kRect_ClipType == clip.getElementType(c)) {
491 SET_RANDOM_COLOR
492 this->drawSimpleRect(clip.getRect(c), NULL, 0);
493 } else {
494 SET_RANDOM_COLOR
bsalomon@google.com7f5875d2011-03-24 16:55:45 +0000495 GrAssert(!IsFillInverted(fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000496 pr->drawPath(this, 0, &pathIter, fill, NULL);
bsalomon@google.comd302f142011-03-03 13:54:13 +0000497 }
498 } else {
499 SET_RANDOM_COLOR
500 this->drawSimpleRect(bounds, 0, NULL);
501 }
502 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000503 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000504 fClip = clip;
505 // recusive draws would have disabled this.
506 fClipState.fClipInStencil = true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000507 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000508
reed@google.comac10a2d2010-12-22 21:39:39 +0000509 fClipState.fClipIsDirty = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000510 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000511
reed@google.comac10a2d2010-12-22 21:39:39 +0000512 // Must flush the scissor after graphics state
bsalomon@google.comd302f142011-03-03 13:54:13 +0000513 if (!this->flushGraphicsState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000514 return false;
515 }
bsalomon@google.comd302f142011-03-03 13:54:13 +0000516 this->flushScissor(r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000517 return true;
518}
519
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000520GrPathRenderer* GrGpu::getClipPathRenderer(GrPathIter* path,
521 GrPathFill fill) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000522 if (NULL != fClientPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000523 fClientPathRenderer->canDrawPath(this, path, fill)) {
524 return fClientPathRenderer;
525 } else {
526 if (NULL == fDefaultPathRenderer) {
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000527 fDefaultPathRenderer =
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000528 new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
529 this->supportsStencilWrapOps());
530 }
531 GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
532 return fDefaultPathRenderer;
533 }
534}
535
536
bsalomon@google.comd302f142011-03-03 13:54:13 +0000537////////////////////////////////////////////////////////////////////////////////
reed@google.comac10a2d2010-12-22 21:39:39 +0000538
bsalomon@google.comffca4002011-02-22 20:34:01 +0000539void GrGpu::drawIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000540 int startVertex,
541 int startIndex,
542 int vertexCount,
543 int indexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000544 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
545 fReservedGeometry.fLocked);
546 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fIndexSrc ||
547 fReservedGeometry.fLocked);
548
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000549 this->handleDirtyContext();
550
551 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000552 return;
553 }
554
555#if GR_COLLECT_STATS
556 fStats.fVertexCnt += vertexCount;
557 fStats.fIndexCnt += indexCount;
558 fStats.fDrawCnt += 1;
559#endif
560
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000561 int sVertex = startVertex;
562 int sIndex = startIndex;
563 setupGeometry(&sVertex, &sIndex, vertexCount, indexCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000564
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000565 drawIndexedHelper(type, sVertex, sIndex,
reed@google.comac10a2d2010-12-22 21:39:39 +0000566 vertexCount, indexCount);
567}
568
bsalomon@google.comffca4002011-02-22 20:34:01 +0000569void GrGpu::drawNonIndexed(GrPrimitiveType type,
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000570 int startVertex,
571 int vertexCount) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000572 GrAssert(kReserved_GeometrySrcType != fGeometrySrc.fVertexSrc ||
573 fReservedGeometry.fLocked);
574
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000575 this->handleDirtyContext();
576
577 if (!this->setupClipAndFlushState(type)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000578 return;
579 }
580#if GR_COLLECT_STATS
581 fStats.fVertexCnt += vertexCount;
582 fStats.fDrawCnt += 1;
583#endif
584
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000585 int sVertex = startVertex;
586 setupGeometry(&sVertex, NULL, vertexCount, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000587
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000588 drawNonIndexedHelper(type, sVertex, vertexCount);
589}
590
591void GrGpu::finalizeReservedVertices() {
592 GrAssert(NULL != fVertexPool);
593 fVertexPool->unlock();
594}
595
596void GrGpu::finalizeReservedIndices() {
597 GrAssert(NULL != fIndexPool);
598 fIndexPool->unlock();
599}
600
601void GrGpu::prepareVertexPool() {
602 if (NULL == fVertexPool) {
bsalomon@google.comd302f142011-03-03 13:54:13 +0000603 fVertexPool = new GrVertexBufferAllocPool(this, true,
604 VERTEX_POOL_VB_SIZE,
bsalomon@google.com7a5af8b2011-02-18 18:40:42 +0000605 VERTEX_POOL_VB_COUNT);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000606 fVertexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000607 } else if (!fVertexPoolInUse) {
608 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000609 fVertexPool->reset();
610 }
611}
612
613void GrGpu::prepareIndexPool() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000614 if (NULL == fIndexPool) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000615 fIndexPool = new GrIndexBufferAllocPool(this, true, 0, 1);
bsalomon@google.com11f0b512011-03-29 20:52:23 +0000616 fIndexPool->releaseGpuRef();
bsalomon@google.comd302f142011-03-03 13:54:13 +0000617 } else if (!fIndexPoolInUse) {
618 // the client doesn't have valid data in the pool
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000619 fIndexPool->reset();
620 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000621}
622
623bool GrGpu::acquireGeometryHelper(GrVertexLayout vertexLayout,
624 void** vertices,
625 void** indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000626 GrAssert(!fReservedGeometry.fLocked);
627 size_t reservedVertexSpace = 0;
628
629 if (fReservedGeometry.fVertexCount) {
630 GrAssert(NULL != vertices);
631
bsalomon@google.comd302f142011-03-03 13:54:13 +0000632 this->prepareVertexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000633
634 *vertices = fVertexPool->makeSpace(vertexLayout,
635 fReservedGeometry.fVertexCount,
636 &fCurrPoolVertexBuffer,
637 &fCurrPoolStartVertex);
638 if (NULL == *vertices) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000639 return false;
640 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000641 reservedVertexSpace = VertexSize(vertexLayout) *
642 fReservedGeometry.fVertexCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000643 }
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000644 if (fReservedGeometry.fIndexCount) {
645 GrAssert(NULL != indices);
646
bsalomon@google.comd302f142011-03-03 13:54:13 +0000647 this->prepareIndexPool();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000648
649 *indices = fIndexPool->makeSpace(fReservedGeometry.fIndexCount,
650 &fCurrPoolIndexBuffer,
651 &fCurrPoolStartIndex);
652 if (NULL == *indices) {
653 fVertexPool->putBack(reservedVertexSpace);
654 fCurrPoolVertexBuffer = NULL;
reed@google.comac10a2d2010-12-22 21:39:39 +0000655 return false;
656 }
657 }
658 return true;
659}
660
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000661void GrGpu::releaseGeometryHelper() {}
662
663void GrGpu::setVertexSourceToArrayHelper(const void* vertexArray, int vertexCount) {
664 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fVertexCount);
665 prepareVertexPool();
666#if GR_DEBUG
667 bool success =
668#endif
669 fVertexPool->appendVertices(fGeometrySrc.fVertexLayout,
670 vertexCount,
671 vertexArray,
672 &fCurrPoolVertexBuffer,
673 &fCurrPoolStartVertex);
674 GR_DEBUGASSERT(success);
675}
676
677void GrGpu::setIndexSourceToArrayHelper(const void* indexArray, int indexCount) {
678 GrAssert(!fReservedGeometry.fLocked || !fReservedGeometry.fIndexCount);
679 prepareIndexPool();
680#if GR_DEBUG
681 bool success =
682#endif
683 fIndexPool->appendIndices(indexCount,
684 indexArray,
685 &fCurrPoolIndexBuffer,
686 &fCurrPoolStartIndex);
687 GR_DEBUGASSERT(success);
reed@google.comac10a2d2010-12-22 21:39:39 +0000688}
689
bsalomon@google.comd302f142011-03-03 13:54:13 +0000690////////////////////////////////////////////////////////////////////////////////
691
reed@google.comac10a2d2010-12-22 21:39:39 +0000692const GrGpu::Stats& GrGpu::getStats() const {
693 return fStats;
694}
695
696void GrGpu::resetStats() {
697 memset(&fStats, 0, sizeof(fStats));
698}
699
700void GrGpu::printStats() const {
701 if (GR_COLLECT_STATS) {
702 GrPrintf(
703 "-v-------------------------GPU STATS----------------------------v-\n"
704 "Stats collection is: %s\n"
705 "Draws: %04d, Verts: %04d, Indices: %04d\n"
706 "ProgChanges: %04d, TexChanges: %04d, RTChanges: %04d\n"
707 "TexCreates: %04d, RTCreates:%04d\n"
708 "-^--------------------------------------------------------------^-\n",
709 (GR_COLLECT_STATS ? "ON" : "OFF"),
710 fStats.fDrawCnt, fStats.fVertexCnt, fStats.fIndexCnt,
711 fStats.fProgChngCnt, fStats.fTextureChngCnt, fStats.fRenderTargetChngCnt,
712 fStats.fTextureCreateCnt, fStats.fRenderTargetCreateCnt);
713 }
714}
715
716////////////////////////////////////////////////////////////////////////////////
717
718GrTexture::~GrTexture() {
719 // use this to set a break-point if needed
720// Gr_clz(3);
721}
722
723const GrSamplerState GrSamplerState::gClampNoFilter(
724 GrSamplerState::kClamp_WrapMode,
725 GrSamplerState::kClamp_WrapMode,
726 GrSamplerState::kNormal_SampleMode,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000727 GrMatrix::I(),
reed@google.comac10a2d2010-12-22 21:39:39 +0000728 false);
729
730
731
732