blob: d14777e23ea551f1c9355d0fd76b581bc44f9827 [file] [log] [blame]
reed@google.com873cb1e2010-12-23 15:00:45 +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 "GrContext.h"
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +000018#include "GrTypes.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000019#include "GrTextureCache.h"
20#include "GrTextStrike.h"
21#include "GrMemory.h"
22#include "GrPathIter.h"
23#include "GrClipIterator.h"
24#include "GrIndexBuffer.h"
bsalomon@google.com1c13c962011-02-14 16:51:21 +000025#include "GrInOrderDrawBuffer.h"
26#include "GrBufferAllocPool.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000027
28#define DEFER_TEXT_RENDERING 1
29
30static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
31static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
32
bsalomon@google.com1c13c962011-02-14 16:51:21 +000033static const uint32_t TEXT_POOL_VB_SIZE = 1 << 18; // enough to draw 4K untextured glyphs
34static const uint32_t NUM_TEXT_POOL_VBS = 4;
reed@google.comac10a2d2010-12-22 21:39:39 +000035
36GrContext* GrContext::Create(GrGpu::Engine engine,
37 GrGpu::Platform3DContext context3D) {
38 GrContext* ctx = NULL;
39 GrGpu* fGpu = GrGpu::Create(engine, context3D);
40 if (NULL != fGpu) {
41 ctx = new GrContext(fGpu);
42 fGpu->unref();
43 }
44 return ctx;
45}
46
reed@google.com873cb1e2010-12-23 15:00:45 +000047GrContext* GrContext::CreateGLShaderContext() {
48 return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
49}
50
reed@google.comac10a2d2010-12-22 21:39:39 +000051GrContext::~GrContext() {
52 fGpu->unref();
53 delete fTextureCache;
54 delete fFontCache;
bsalomon@google.com1c13c962011-02-14 16:51:21 +000055 delete fTextDrawBuffer;
56 delete fTextVBAllocPool;
57 delete fTextIBAllocPool;
reed@google.comac10a2d2010-12-22 21:39:39 +000058}
59
60void GrContext::abandonAllTextures() {
61 fTextureCache->deleteAll(GrTextureCache::kAbandonTexture_DeleteMode);
62 fFontCache->abandonAll();
63}
64
65GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
66 const GrSamplerState& sampler) {
67 finalizeTextureKey(key, sampler);
68 return fTextureCache->findAndLock(*key);
69}
70
71static void stretchImage(void* dst,
72 int dstW,
73 int dstH,
74 void* src,
75 int srcW,
76 int srcH,
77 int bpp) {
78 GrFixed dx = (srcW << 16) / dstW;
79 GrFixed dy = (srcH << 16) / dstH;
80
81 GrFixed y = dy >> 1;
82
83 int dstXLimit = dstW*bpp;
84 for (int j = 0; j < dstH; ++j) {
85 GrFixed x = dx >> 1;
86 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
87 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
88 for (int i = 0; i < dstXLimit; i += bpp) {
89 memcpy((uint8_t*) dstRow + i,
90 (uint8_t*) srcRow + (x>>16)*bpp,
91 bpp);
92 x += dx;
93 }
94 y += dy;
95 }
96}
97
98GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
99 const GrSamplerState& sampler,
100 const GrGpu::TextureDesc& desc,
101 void* srcData, size_t rowBytes) {
102 GrAssert(key->width() == desc.fWidth);
103 GrAssert(key->height() == desc.fHeight);
104
105#if GR_DUMP_TEXTURE_UPLOAD
106 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
107#endif
108
109 GrTextureEntry* entry = NULL;
110 bool special = finalizeTextureKey(key, sampler);
111 if (special) {
112 GrTextureEntry* clampEntry;
113 GrTextureKey clampKey(*key);
114 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
115
116 if (NULL == clampEntry) {
117 clampEntry = createAndLockTexture(&clampKey,
118 GrSamplerState::ClampNoFilter(),
119 desc, srcData, rowBytes);
120 GrAssert(NULL != clampEntry);
121 if (NULL == clampEntry) {
122 return NULL;
123 }
124 }
125 GrTexture* clampTexture = clampEntry->texture();
126 GrGpu::TextureDesc rtDesc = desc;
127 rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag |
128 GrGpu::kNoPathRendering_TextureFlag;
129 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
130 fGpu->minRenderTargetWidth()));
131 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
132 fGpu->minRenderTargetHeight()));
133
134 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
135
136 if (NULL != texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000137 GrDrawTarget::AutoStateRestore asr(fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000138 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000139 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000140 fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000141 fGpu->setTextureMatrix(0, GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000142 fGpu->setViewMatrix(GrMatrix::I());
143 fGpu->setAlpha(0xff);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000144 fGpu->setBlendFunc(GrDrawTarget::kOne_BlendCoeff, GrDrawTarget::kZero_BlendCoeff);
145 fGpu->disableState(GrDrawTarget::kDither_StateBit |
146 GrDrawTarget::kClip_StateBit |
147 GrDrawTarget::kAntialias_StateBit);
reed@google.comac10a2d2010-12-22 21:39:39 +0000148 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
149 GrSamplerState::kClamp_WrapMode,
150 sampler.isFilter());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000151 fGpu->setSamplerState(0, stretchSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000152
153 static const GrVertexLayout layout =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000154 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000155 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
156
157 if (arg.succeeded()) {
158 GrPoint* verts = (GrPoint*) arg.vertices();
159 verts[0].setIRectFan(0, 0,
160 texture->contentWidth(),
161 texture->contentHeight(),
162 2*sizeof(GrPoint));
163 GrScalar tw = GrFixedToScalar(GR_Fixed1 *
164 clampTexture->contentWidth() /
165 clampTexture->allocWidth());
166 GrScalar th = GrFixedToScalar(GR_Fixed1 *
167 clampTexture->contentHeight() /
168 clampTexture->allocHeight());
169 verts[1].setRectFan(0, 0, tw, th, 2*sizeof(GrPoint));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000170 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000171 0, 4);
172 entry = fTextureCache->createAndLock(*key, texture);
173 }
174 texture->removeRenderTarget();
175 } else {
176 // TODO: Our CPU stretch doesn't filter. But we create separate
177 // stretched textures when the sampler state is either filtered or
178 // not. Either implement filtered stretch blit on CPU or just create
179 // one when FBO case fails.
180
181 rtDesc.fFlags = 0;
182 // no longer need to clamp at min RT size.
183 rtDesc.fWidth = GrNextPow2(desc.fWidth);
184 rtDesc.fHeight = GrNextPow2(desc.fHeight);
185 int bpp = GrTexture::BytesPerPixel(desc.fFormat);
186 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
187 rtDesc.fWidth *
188 rtDesc.fHeight);
189 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
190 srcData, desc.fWidth, desc.fHeight, bpp);
191
192 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
193
194 GrTexture* texture = fGpu->createTexture(rtDesc,
195 stretchedPixels.get(),
196 stretchedRowBytes);
197 GrAssert(NULL != texture);
198 entry = fTextureCache->createAndLock(*key, texture);
199 }
200 fTextureCache->unlock(clampEntry);
201
202 } else {
203 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
204 if (NULL != texture) {
205 entry = fTextureCache->createAndLock(*key, texture);
206 } else {
207 entry = NULL;
208 }
209 }
210 return entry;
211}
212
213void GrContext::unlockTexture(GrTextureEntry* entry) {
214 fTextureCache->unlock(entry);
215}
216
217void GrContext::detachCachedTexture(GrTextureEntry* entry) {
218 fTextureCache->detach(entry);
219}
220
221void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) {
222 fTextureCache->reattachAndUnlock(entry);
223}
224
225GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc,
226 void* srcData,
227 size_t rowBytes) {
228 return fGpu->createTexture(desc, srcData, rowBytes);
229}
230
reed@google.com01804b42011-01-18 21:50:41 +0000231void GrContext::getTextureCacheLimits(int* maxTextures,
232 size_t* maxTextureBytes) const {
233 fTextureCache->getLimits(maxTextures, maxTextureBytes);
234}
235
236void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
237 fTextureCache->setLimits(maxTextures, maxTextureBytes);
238}
239
reed@google.com02a7e6c2011-01-28 21:21:49 +0000240int GrContext::getMaxTextureDimension() {
241 return fGpu->maxTextureDimension();
242}
243
reed@google.com01804b42011-01-18 21:50:41 +0000244///////////////////////////////////////////////////////////////////////////////
245
reed@google.comac10a2d2010-12-22 21:39:39 +0000246GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,
247 int width, int height) {
248 return fGpu->createPlatformRenderTarget(platformRenderTarget,
249 width, height);
250}
251
252bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
253 int width, int height) {
254 if (!fGpu->supports8BitPalette()) {
255 return false;
256 }
257
bsalomon@google.com0748f212011-02-01 22:56:16 +0000258
reed@google.comac10a2d2010-12-22 21:39:39 +0000259 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
260
bsalomon@google.com0748f212011-02-01 22:56:16 +0000261 if (!isPow2) {
262 if (!fGpu->npotTextureSupport()) {
263 return false;
264 }
265
266 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
267 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
268 if (tiled && !fGpu->npotTextureTileSupport()) {
269 return false;
270 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000271 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000272 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000273}
274
275////////////////////////////////////////////////////////////////////////////////
276
bsalomon@google.com5782d712011-01-21 21:03:59 +0000277void GrContext::setClip(const GrClip& clip) {
278 fGpu->setClip(clip);
279 fGpu->enableState(GrDrawTarget::kClip_StateBit);
280}
281
282void GrContext::setClip(const GrIRect& rect) {
283 GrClip clip;
284 clip.setRect(rect);
285 fGpu->setClip(clip);
286}
287
288////////////////////////////////////////////////////////////////////////////////
289
reed@google.comac10a2d2010-12-22 21:39:39 +0000290void GrContext::eraseColor(GrColor color) {
291 fGpu->eraseColor(color);
292}
293
bsalomon@google.com5782d712011-01-21 21:03:59 +0000294void GrContext::drawPaint(const GrPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000295 // set rect to be big enough to fill the space, but not super-huge, so we
296 // don't overflow fixed-point implementations
297 GrRect r(fGpu->getClip().getBounds());
298 GrMatrix inverse;
299 if (fGpu->getViewInverse(&inverse)) {
300 inverse.mapRect(&r);
301 } else {
302 GrPrintf("---- fGpu->getViewInverse failed\n");
303 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000304 this->drawRect(paint, r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000305}
306
307/* create a triangle strip that strokes the specified triangle. There are 8
308 unique vertices, but we repreat the last 2 to close up. Alternatively we
309 could use an indices array, and then only send 8 verts, but not sure that
310 would be faster.
311 */
312static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
313 GrScalar width) {
314 const GrScalar rad = GrScalarHalf(width);
315
316 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
317 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
318 verts[2].set(rect.fRight - rad, rect.fTop + rad);
319 verts[3].set(rect.fRight + rad, rect.fTop - rad);
320 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
321 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
322 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
323 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
324 verts[8] = verts[0];
325 verts[9] = verts[1];
326}
327
bsalomon@google.com5782d712011-01-21 21:03:59 +0000328void GrContext::drawRect(const GrPaint& paint,
329 const GrRect& rect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000330 GrScalar width,
331 const GrMatrix* matrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000332
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000333 bool textured = NULL != paint.getTexture();
334 GrVertexLayout layout = (textured) ?
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000335 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
reed@google.comac10a2d2010-12-22 21:39:39 +0000336 0;
337
bsalomon@google.com5782d712011-01-21 21:03:59 +0000338 this->prepareToDraw(paint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000339
reed@google.comac10a2d2010-12-22 21:39:39 +0000340 if (width >= 0) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000341 // TODO: consider making static vertex buffers for these cases.
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000342 // Hairline could be done by just adding closing vertex to
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000343 // unitSquareVertexBuffer()
344 static const int worstCaseVertCount = 10;
345 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, worstCaseVertCount, 0);
346
347 if (!geo.succeeded()) {
348 return;
349 }
350
351 GrDrawTarget::PrimitiveType primType;
352 int vertCount;
353 GrPoint* vertex = geo.positions();
354
reed@google.comac10a2d2010-12-22 21:39:39 +0000355 if (width > 0) {
356 vertCount = 10;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000357 primType = GrDrawTarget::kTriangleStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000358 setStrokeRectStrip(vertex, rect, width);
359 } else {
360 // hairline
361 vertCount = 5;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000362 primType = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000363 vertex[0].set(rect.fLeft, rect.fTop);
364 vertex[1].set(rect.fRight, rect.fTop);
365 vertex[2].set(rect.fRight, rect.fBottom);
366 vertex[3].set(rect.fLeft, rect.fBottom);
367 vertex[4].set(rect.fLeft, rect.fTop);
368 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000369
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000370 GrDrawTarget::AutoViewMatrixRestore avmr;
371 if (NULL != matrix) {
372 avmr.set(fGpu);
373 fGpu->concatViewMatrix(*matrix);
374 fGpu->concatTextureMatrix(0, *matrix);
375 }
376
377 fGpu->drawNonIndexed(primType, 0, vertCount);
378 } else {
bsalomon@google.com43333232011-02-02 19:24:54 +0000379 #if GR_STATIC_RECT_VB
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000380 fGpu->setVertexSourceToBuffer(fGpu->unitSquareVertexBuffer(), layout);
381 GrDrawTarget::AutoViewMatrixRestore avmr(fGpu);
382 GrMatrix m;
383 m.setAll(rect.width(), 0, rect.fLeft,
384 0, rect.height(), rect.fTop,
385 0, 0, GrMatrix::I()[8]);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000386
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000387 if (NULL != matrix) {
388 m.postConcat(*matrix);
389 }
390
391 fGpu->concatViewMatrix(m);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000392
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000393 if (textured) {
394 fGpu->concatTextureMatrix(0, m);
395 }
396 #else
397 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, 4, 0);
398 GrPoint* vertex = geo.positions();
399 vertex->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
400
401 GrDrawTarget::AutoViewMatrixRestore avmr;
402 if (NULL != matrix) {
403 avmr.set(fGpu);
404 fGpu->concatViewMatrix(*matrix);
405 fGpu->concatTextureMatrix(0, *matrix);
406 }
407 #endif
408
409 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
410 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000411}
412
bsalomon@google.com5782d712011-01-21 21:03:59 +0000413void GrContext::drawRectToRect(const GrPaint& paint,
414 const GrRect& dstRect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000415 const GrRect& srcRect,
416 const GrMatrix* dstMatrix,
417 const GrMatrix* srcMatrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000418
419 if (NULL == paint.getTexture()) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000420 drawRect(paint, dstRect, -1, dstMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000421 return;
422 }
423
424 this->prepareToDraw(paint);
425
bsalomon@google.com43333232011-02-02 19:24:54 +0000426#if GR_STATIC_RECT_VB
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000427 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
428 GrDrawTarget::AutoViewMatrixRestore avmr(fGpu);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000429
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000430 GrMatrix m;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000431
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000432 m.setAll(dstRect.width(), 0, dstRect.fLeft,
433 0, dstRect.height(), dstRect.fTop,
434 0, 0, GrMatrix::I()[8]);
435 if (NULL != dstMatrix) {
436 m.postConcat(*dstMatrix);
437 }
438 fGpu->concatViewMatrix(m);
439
440 m.setAll(srcRect.width(), 0, srcRect.fLeft,
441 0, srcRect.height(), srcRect.fTop,
442 0, 0, GrMatrix::I()[8]);
443 if (NULL != srcMatrix) {
444 m.postConcat(*srcMatrix);
445 }
446 fGpu->concatTextureMatrix(0, m);
447
448 fGpu->setVertexSourceToBuffer(fGpu->unitSquareVertexBuffer(), layout);
449#else
450 GrVertexLayout layout = GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
451
452 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, 4, 0);
453 GrPoint* pos = geo.positions();
454 GrPoint* tex = pos + 1;
455 static const size_t stride = 2 * sizeof(GrPoint);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000456 pos[0].setRectFan(dstRect.fLeft, dstRect.fTop,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000457 dstRect.fRight, dstRect.fBottom,
458 stride);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000459 tex[0].setRectFan(srcRect.fLeft, srcRect.fTop,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000460 srcRect.fRight, srcRect.fBottom,
461 stride);
462
463 GrDrawTarget::AutoViewMatrixRestore avmr;
464 if (NULL != dstMatrix) {
465 avmr.set(fGpu);
466 fGpu->concatViewMatrix(*dstMatrix);
467 }
468 if (NULL != srcMatrix) {
469 fGpu->concatTextureMatrix(0, *srcMatrix);
470 }
471
472#endif
473 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000474}
475
476void GrContext::drawVertices(const GrPaint& paint,
477 GrDrawTarget::PrimitiveType primitiveType,
478 int vertexCount,
479 const GrPoint positions[],
480 const GrPoint texCoords[],
481 const GrColor colors[],
482 const uint16_t indices[],
483 int indexCount) {
484 GrVertexLayout layout = 0;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000485 int vertexSize = sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000486
487 GrDrawTarget::AutoReleaseGeometry geo;
488
489 this->prepareToDraw(paint);
490
491 if (NULL != paint.getTexture()) {
492 if (NULL == texCoords) {
493 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
494 } else {
495 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000496 vertexSize += sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000497 }
498 }
499
500 if (NULL != colors) {
501 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000502 vertexSize += sizeof(GrColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000503 }
504
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000505 if (sizeof(GrPoint) != vertexSize) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000506 if (!geo.set(fGpu, layout, vertexCount, 0)) {
507 GrPrintf("Failed to get space for vertices!");
508 return;
509 }
510 int texOffsets[GrDrawTarget::kMaxTexCoords];
511 int colorOffset;
512 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
513 texOffsets,
514 &colorOffset);
515 void* curVertex = geo.vertices();
516
517 for (int i = 0; i < vertexCount; ++i) {
518 *((GrPoint*)curVertex) = positions[i];
519
520 if (texOffsets[0] > 0) {
521 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
522 }
523 if (colorOffset > 0) {
524 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
525 }
526 curVertex = (void*)((intptr_t)curVertex + vsize);
527 }
528 } else {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000529 fGpu->setVertexSourceToArray(layout, positions, vertexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000530 }
531
532 if (NULL != indices) {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000533 fGpu->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000534 fGpu->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
535 } else {
536 fGpu->drawNonIndexed(primitiveType, 0, vertexCount);
537 }
538}
539
540
reed@google.comac10a2d2010-12-22 21:39:39 +0000541////////////////////////////////////////////////////////////////////////////////
542
reed@google.comac10a2d2010-12-22 21:39:39 +0000543#define STENCIL_OFF 0 // Always disable stencil (even when needed)
reed@google.comac10a2d2010-12-22 21:39:39 +0000544#define EVAL_TOL GR_Scalar1
545
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000546static const uint32_t MAX_POINTS_PER_CURVE = 1 << 10;
547
reed@google.comac10a2d2010-12-22 21:39:39 +0000548static uint32_t quadratic_point_count(const GrPoint points[], GrScalar tol) {
549 GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
550 // TODO: fixed points sqrt
551 if (d < tol) {
552 return 1;
553 } else {
554 // Each time we subdivide, d should be cut in 4. So we need to
555 // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
556 // points.
557 // 2^(log4(x)) = sqrt(x);
558 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000559 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000560 }
561}
562
563static uint32_t generate_quadratic_points(const GrPoint& p0,
564 const GrPoint& p1,
565 const GrPoint& p2,
566 GrScalar tolSqd,
567 GrPoint** points,
568 uint32_t pointsLeft) {
569 if (pointsLeft < 2 ||
570 (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
571 (*points)[0] = p2;
572 *points += 1;
573 return 1;
574 }
575
576 GrPoint q[] = {
577 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
578 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
579 };
580 GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY));
581
582 pointsLeft >>= 1;
583 uint32_t a = generate_quadratic_points(p0, q[0], r, tolSqd, points, pointsLeft);
584 uint32_t b = generate_quadratic_points(r, q[1], p2, tolSqd, points, pointsLeft);
585 return a + b;
586}
587
588static uint32_t cubic_point_count(const GrPoint points[], GrScalar tol) {
589 GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
590 points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
591 d = sqrtf(d);
592 if (d < tol) {
593 return 1;
594 } else {
595 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000596 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000597 }
598}
599
600static uint32_t generate_cubic_points(const GrPoint& p0,
601 const GrPoint& p1,
602 const GrPoint& p2,
603 const GrPoint& p3,
604 GrScalar tolSqd,
605 GrPoint** points,
606 uint32_t pointsLeft) {
607 if (pointsLeft < 2 ||
608 (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
609 p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
610 (*points)[0] = p3;
611 *points += 1;
612 return 1;
613 }
614 GrPoint q[] = {
615 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
616 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
617 GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY))
618 };
619 GrPoint r[] = {
620 GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)),
621 GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY))
622 };
623 GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY));
624 pointsLeft >>= 1;
625 uint32_t a = generate_cubic_points(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
626 uint32_t b = generate_cubic_points(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
627 return a + b;
628}
629
reed@google.comac10a2d2010-12-22 21:39:39 +0000630static int worst_case_point_count(GrPathIter* path,
631 int* subpaths,
reed@google.comac10a2d2010-12-22 21:39:39 +0000632 GrScalar tol) {
633 int pointCount = 0;
634 *subpaths = 1;
635
636 bool first = true;
637
638 GrPathIter::Command cmd;
639
640 GrPoint pts[4];
641 while ((cmd = path->next(pts)) != GrPathIter::kEnd_Command) {
642
643 switch (cmd) {
644 case GrPathIter::kLine_Command:
645 pointCount += 1;
646 break;
647 case GrPathIter::kQuadratic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000648 pointCount += quadratic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000649 break;
650 case GrPathIter::kCubic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000651 pointCount += cubic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000652 break;
653 case GrPathIter::kMove_Command:
654 pointCount += 1;
655 if (!first) {
656 ++(*subpaths);
657 }
658 break;
659 default:
660 break;
661 }
662 first = false;
663 }
664 return pointCount;
665}
666
667static inline bool single_pass_path(const GrPathIter& path,
668 GrContext::PathFills fill,
reed@google.comac10a2d2010-12-22 21:39:39 +0000669 const GrGpu& gpu) {
670#if STENCIL_OFF
671 return true;
672#else
673 if (GrContext::kEvenOdd_PathFill == fill) {
674 GrPathIter::ConvexHint hint = path.hint();
675 return hint == GrPathIter::kConvex_ConvexHint ||
676 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint;
677 } else if (GrContext::kWinding_PathFill == fill) {
678 GrPathIter::ConvexHint hint = path.hint();
679 return hint == GrPathIter::kConvex_ConvexHint ||
680 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint ||
681 (hint == GrPathIter::kSameWindingConvexPieces_ConvexHint &&
682 gpu.canDisableBlend() && !gpu.isDitherState());
683
684 }
685 return false;
686#endif
687}
688
bsalomon@google.com5782d712011-01-21 21:03:59 +0000689void GrContext::drawPath(const GrPaint& paint,
690 GrPathIter* path,
691 PathFills fill,
692 const GrPoint* translate) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000693
reed@google.comac10a2d2010-12-22 21:39:39 +0000694
bsalomon@google.com5782d712011-01-21 21:03:59 +0000695 this->prepareToDraw(paint);
696
697 GrDrawTarget::AutoStateRestore asr(fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000698
bsalomon@google.com5782d712011-01-21 21:03:59 +0000699 GrMatrix viewM = fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000700 // In order to tesselate the path we get a bound on how much the matrix can
701 // stretch when mapping to screen coordinates.
702 GrScalar stretch = viewM.getMaxStretch();
703 bool useStretch = stretch > 0;
704 GrScalar tol = EVAL_TOL;
705 if (!useStretch) {
706 // TODO: deal with perspective in some better way.
707 tol /= 10;
708 } else {
709 // TODO: fixed point divide
710 GrScalar sinv = 1 / stretch;
711 tol = GrMul(tol, sinv);
reed@google.comac10a2d2010-12-22 21:39:39 +0000712 }
713 GrScalar tolSqd = GrMul(tol, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000714
715 int subpathCnt;
716 int maxPts = worst_case_point_count(path,
717 &subpathCnt,
reed@google.comac10a2d2010-12-22 21:39:39 +0000718 tol);
719 GrVertexLayout layout = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000720
721 if (NULL != paint.getTexture()) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000722 layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000723 }
724 // add 4 to hold the bounding rect
725 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, maxPts + 4, 0);
726
727 GrPoint* base = (GrPoint*) arg.vertices();
728 GrPoint* vert = base;
729 GrPoint* subpathBase = base;
730
731 GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
732
733 path->rewind();
734
735 // TODO: use primitve restart if available rather than multiple draws
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000736 GrDrawTarget::PrimitiveType type;
737 int passCount = 0;
738 GrDrawTarget::StencilPass passes[3];
739 bool reverse = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000740
741 if (kHairLine_PathFill == fill) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000742 type = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000743 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000744 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000745 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000746 type = GrDrawTarget::kTriangleFan_PrimitiveType;
747 if (single_pass_path(*path, fill, *fGpu)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000748 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000749 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000750 } else {
751 switch (fill) {
752 case kInverseEvenOdd_PathFill:
753 reverse = true;
754 // fallthrough
755 case kEvenOdd_PathFill:
756 passCount = 2;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000757 passes[0] = GrDrawTarget::kEvenOddStencil_StencilPass;
758 passes[1] = GrDrawTarget::kEvenOddColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000759 break;
760
761 case kInverseWinding_PathFill:
762 reverse = true;
763 // fallthrough
764 case kWinding_PathFill:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000765 passes[0] = GrDrawTarget::kWindingStencil1_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000766 if (fGpu->supportsSingleStencilPassWinding()) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000767 passes[1] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000768 passCount = 2;
769 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000770 passes[1] = GrDrawTarget::kWindingStencil2_StencilPass;
771 passes[2] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000772 passCount = 3;
773 }
774 break;
775 default:
776 GrAssert(!"Unknown path fill!");
777 return;
778 }
779 }
780 }
781 fGpu->setReverseFill(reverse);
reed@google.comac10a2d2010-12-22 21:39:39 +0000782
783 GrPoint pts[4];
784
785 bool first = true;
786 int subpath = 0;
787
788 for (;;) {
789 GrPathIter::Command cmd = path->next(pts);
reed@google.comac10a2d2010-12-22 21:39:39 +0000790 switch (cmd) {
791 case GrPathIter::kMove_Command:
792 if (!first) {
793 subpathVertCount[subpath] = vert-subpathBase;
794 subpathBase = vert;
795 ++subpath;
796 }
797 *vert = pts[0];
798 vert++;
799 break;
800 case GrPathIter::kLine_Command:
801 *vert = pts[1];
802 vert++;
803 break;
804 case GrPathIter::kQuadratic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000805 generate_quadratic_points(pts[0], pts[1], pts[2],
806 tolSqd, &vert,
807 quadratic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000808 break;
809 }
810 case GrPathIter::kCubic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000811 generate_cubic_points(pts[0], pts[1], pts[2], pts[3],
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000812 tolSqd, &vert,
reed@google.comac10a2d2010-12-22 21:39:39 +0000813 cubic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000814 break;
815 }
816 case GrPathIter::kClose_Command:
817 break;
818 case GrPathIter::kEnd_Command:
819 subpathVertCount[subpath] = vert-subpathBase;
820 ++subpath; // this could be only in debug
821 goto FINISHED;
822 }
823 first = false;
824 }
825FINISHED:
826 GrAssert(subpath == subpathCnt);
827 GrAssert((vert - base) <= maxPts);
828
829 if (translate) {
830 int count = vert - base;
831 for (int i = 0; i < count; i++) {
832 base[i].offset(translate->fX, translate->fY);
833 }
834 }
835
836 // arbitrary path complexity cutoff
837 bool useBounds = fill != kHairLine_PathFill &&
838 (reverse || (vert - base) > 8);
839 GrPoint* boundsVerts = base + maxPts;
840 if (useBounds) {
841 GrRect bounds;
842 if (reverse) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000843 GrAssert(NULL != fGpu->getRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000844 // draw over the whole world.
845 bounds.setLTRB(0, 0,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000846 GrIntToScalar(fGpu->getRenderTarget()->width()),
847 GrIntToScalar(fGpu->getRenderTarget()->height()));
848 GrMatrix vmi;
849 if (fGpu->getViewInverse(&vmi)) {
850 vmi.mapRect(&bounds);
851 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000852 } else {
853 bounds.setBounds((GrPoint*)base, vert - base);
854 }
855 boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
856 bounds.fBottom);
857 }
858
859 for (int p = 0; p < passCount; ++p) {
860 fGpu->setStencilPass(passes[p]);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000861 if (useBounds && (GrDrawTarget::kEvenOddColor_StencilPass == passes[p] ||
862 GrDrawTarget::kWindingColor_StencilPass == passes[p])) {
863 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000864 maxPts, 4);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000865
reed@google.comac10a2d2010-12-22 21:39:39 +0000866 } else {
867 int baseVertex = 0;
868 for (int sp = 0; sp < subpathCnt; ++sp) {
869 fGpu->drawNonIndexed(type,
870 baseVertex,
871 subpathVertCount[sp]);
872 baseVertex += subpathVertCount[sp];
873 }
874 }
875 }
876}
877
bsalomon@google.com5782d712011-01-21 21:03:59 +0000878////////////////////////////////////////////////////////////////////////////////
879
reed@google.comac10a2d2010-12-22 21:39:39 +0000880void GrContext::flush(bool flushRenderTarget) {
881 flushText();
882 if (flushRenderTarget) {
883 fGpu->forceRenderTargetFlush();
884 }
885}
886
887void GrContext::flushText() {
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000888 if (NULL != fTextDrawBuffer) {
889 fTextDrawBuffer->playback(fGpu);
890 fTextDrawBuffer->reset();
891 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000892}
893
894bool GrContext::readPixels(int left, int top, int width, int height,
895 GrTexture::PixelConfig config, void* buffer) {
896 this->flush(true);
897 return fGpu->readPixels(left, top, width, height, config, buffer);
898}
899
900void GrContext::writePixels(int left, int top, int width, int height,
901 GrTexture::PixelConfig config, const void* buffer,
902 size_t stride) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000903
904 // TODO: when underlying api has a direct way to do this we should use it
905 // (e.g. glDrawPixels on desktop GL).
906
reed@google.comac10a2d2010-12-22 21:39:39 +0000907 const GrGpu::TextureDesc desc = {
908 0, GrGpu::kNone_AALevel, width, height, config
909 };
910 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
911 if (NULL == texture) {
912 return;
913 }
914
915 this->flush(true);
916
917 GrAutoUnref aur(texture);
918 GrDrawTarget::AutoStateRestore asr(fGpu);
919
920 GrMatrix matrix;
921 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
922 fGpu->setViewMatrix(matrix);
923 matrix.setScale(GR_Scalar1 / texture->allocWidth(),
924 GR_Scalar1 / texture->allocHeight());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000925 fGpu->setTextureMatrix(0, matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000926
927 fGpu->disableState(GrDrawTarget::kClip_StateBit);
928 fGpu->setAlpha(0xFF);
929 fGpu->setBlendFunc(GrDrawTarget::kOne_BlendCoeff,
930 GrDrawTarget::kZero_BlendCoeff);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000931 fGpu->setTexture(0, texture);
932 fGpu->setSamplerState(0, GrSamplerState::ClampNoFilter());
reed@google.comac10a2d2010-12-22 21:39:39 +0000933
bsalomon@google.com5782d712011-01-21 21:03:59 +0000934 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
935 static const int VCOUNT = 4;
936
937 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
938 if (!geo.succeeded()) {
939 return;
940 }
941 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
942 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, VCOUNT);
943}
944////////////////////////////////////////////////////////////////////////////////
945
946void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
947 target->setTexture(0, paint.getTexture());
948 target->setTextureMatrix(0, paint.fTextureMatrix);
949 target->setSamplerState(0, paint.fSampler);
950 target->setColor(paint.fColor);
951
952 if (paint.fDither) {
953 target->enableState(GrDrawTarget::kDither_StateBit);
954 } else {
955 target->disableState(GrDrawTarget::kDither_StateBit);
956 }
957 if (paint.fAntiAlias) {
958 target->enableState(GrDrawTarget::kAntialias_StateBit);
959 } else {
960 target->disableState(GrDrawTarget::kAntialias_StateBit);
961 }
962 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
963}
964
965void GrContext::prepareToDraw(const GrPaint& paint) {
966
967 flushText();
968 SetPaint(paint, fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000969}
970
971////////////////////////////////////////////////////////////////////////////////
972
reed@google.comac10a2d2010-12-22 21:39:39 +0000973void GrContext::resetContext() {
974 fGpu->resetContext();
975}
976
reed@google.comac10a2d2010-12-22 21:39:39 +0000977void GrContext::setRenderTarget(GrRenderTarget* target) {
978 flushText();
979 fGpu->setRenderTarget(target);
980}
981
bsalomon@google.com5782d712011-01-21 21:03:59 +0000982GrRenderTarget* GrContext::getRenderTarget() {
983 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +0000984}
985
bsalomon@google.com5782d712011-01-21 21:03:59 +0000986const GrRenderTarget* GrContext::getRenderTarget() const {
987 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +0000988}
989
bsalomon@google.com5782d712011-01-21 21:03:59 +0000990const GrMatrix& GrContext::getMatrix() const {
991 return fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000992}
993
bsalomon@google.com5782d712011-01-21 21:03:59 +0000994void GrContext::setMatrix(const GrMatrix& m) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000995 fGpu->setViewMatrix(m);
996}
997
bsalomon@google.com5782d712011-01-21 21:03:59 +0000998void GrContext::concatMatrix(const GrMatrix& m) const {
999 fGpu->concatViewMatrix(m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001000}
1001
1002static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1003 intptr_t mask = 1 << shift;
1004 if (pred) {
1005 bits |= mask;
1006 } else {
1007 bits &= ~mask;
1008 }
1009 return bits;
1010}
1011
reed@google.comac10a2d2010-12-22 21:39:39 +00001012void GrContext::resetStats() {
1013 fGpu->resetStats();
1014}
1015
1016const GrGpu::Stats& GrContext::getStats() const {
1017 return fGpu->getStats();
1018}
1019
1020void GrContext::printStats() const {
1021 fGpu->printStats();
1022}
1023
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001024GrContext::GrContext(GrGpu* gpu) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001025 fGpu = gpu;
1026 fGpu->ref();
1027 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1028 MAX_TEXTURE_CACHE_BYTES);
1029 fFontCache = new GrFontCache(fGpu);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001030
1031#if DEFER_TEXT_RENDERING
1032 fTextVBAllocPool = new GrVertexBufferAllocPool(gpu,
1033 false,
1034 TEXT_POOL_VB_SIZE,
1035 NUM_TEXT_POOL_VBS);
1036 fTextIBAllocPool = new GrIndexBufferAllocPool(gpu, false, 0, 0);
1037
1038 fTextDrawBuffer = new GrInOrderDrawBuffer(fTextVBAllocPool,
1039 fTextIBAllocPool);
1040#else
1041 fTextDrawBuffer = NULL;
1042 fTextVBAllocPool = NULL;
1043 fTextIBAllocPool = NULL;
1044#endif
1045
reed@google.comac10a2d2010-12-22 21:39:39 +00001046}
1047
1048bool GrContext::finalizeTextureKey(GrTextureKey* key,
1049 const GrSamplerState& sampler) const {
1050 uint32_t bits = 0;
1051 uint16_t width = key->width();
1052 uint16_t height = key->height();
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001053
bsalomon@google.com0748f212011-02-01 22:56:16 +00001054
1055 if (!fGpu->npotTextureTileSupport()) {
1056 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
1057
1058 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
1059 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
1060
1061 if (tiled && !isPow2) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001062 bits |= 1;
1063 bits |= sampler.isFilter() ? 2 : 0;
1064 }
1065 }
1066 key->finalize(bits);
1067 return 0 != bits;
1068}
1069
bsalomon@google.com5782d712011-01-21 21:03:59 +00001070GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1071 GrDrawTarget* target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001072#if DEFER_TEXT_RENDERING
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001073 fTextDrawBuffer->initializeDrawStateAndClip(*fGpu);
1074 target = fTextDrawBuffer;
reed@google.comac10a2d2010-12-22 21:39:39 +00001075#else
bsalomon@google.com5782d712011-01-21 21:03:59 +00001076 target = fGpu;
reed@google.comac10a2d2010-12-22 21:39:39 +00001077#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +00001078 SetPaint(paint, target);
1079 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001080}
1081
1082const GrIndexBuffer* GrContext::quadIndexBuffer() const {
1083 return fGpu->quadIndexBuffer();
1084}
1085
1086int GrContext::maxQuadsInIndexBuffer() const {
1087 return fGpu->maxQuadsInIndexBuffer();
1088}
1089
1090
1091