blob: e224891a92bf6249154456752e559c8623e41cda [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
18#include "GrContext.h"
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +000019#include "GrTypes.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000020#include "GrTextureCache.h"
21#include "GrTextStrike.h"
22#include "GrMemory.h"
23#include "GrPathIter.h"
24#include "GrClipIterator.h"
25#include "GrIndexBuffer.h"
26
27#define DEFER_TEXT_RENDERING 1
28
29static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
30static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
31
32#if DEFER_TEXT_RENDERING
33 static const uint32_t POOL_VB_SIZE = 2048 *
bsalomon@google.com2e7b43d2011-01-18 20:57:22 +000034 GrDrawTarget::VertexSize(
35 GrDrawTarget::kTextFormat_VertexLayoutBit |
bsalomon@google.com1572b072011-01-18 15:30:57 +000036 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0));
reed@google.comac10a2d2010-12-22 21:39:39 +000037 static const uint32_t NUM_POOL_VBS = 8;
38#else
39 static const uint32_t POOL_VB_SIZE = 0;
40 static const uint32_t NUM_POOL_VBS = 0;
41
42#endif
43
44GrContext* GrContext::Create(GrGpu::Engine engine,
45 GrGpu::Platform3DContext context3D) {
46 GrContext* ctx = NULL;
47 GrGpu* fGpu = GrGpu::Create(engine, context3D);
48 if (NULL != fGpu) {
49 ctx = new GrContext(fGpu);
50 fGpu->unref();
51 }
52 return ctx;
53}
54
reed@google.com873cb1e2010-12-23 15:00:45 +000055GrContext* GrContext::CreateGLShaderContext() {
56 return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
57}
58
reed@google.comac10a2d2010-12-22 21:39:39 +000059GrContext::~GrContext() {
60 fGpu->unref();
61 delete fTextureCache;
62 delete fFontCache;
63}
64
65void GrContext::abandonAllTextures() {
66 fTextureCache->deleteAll(GrTextureCache::kAbandonTexture_DeleteMode);
67 fFontCache->abandonAll();
68}
69
70GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
71 const GrSamplerState& sampler) {
72 finalizeTextureKey(key, sampler);
73 return fTextureCache->findAndLock(*key);
74}
75
76static void stretchImage(void* dst,
77 int dstW,
78 int dstH,
79 void* src,
80 int srcW,
81 int srcH,
82 int bpp) {
83 GrFixed dx = (srcW << 16) / dstW;
84 GrFixed dy = (srcH << 16) / dstH;
85
86 GrFixed y = dy >> 1;
87
88 int dstXLimit = dstW*bpp;
89 for (int j = 0; j < dstH; ++j) {
90 GrFixed x = dx >> 1;
91 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
92 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
93 for (int i = 0; i < dstXLimit; i += bpp) {
94 memcpy((uint8_t*) dstRow + i,
95 (uint8_t*) srcRow + (x>>16)*bpp,
96 bpp);
97 x += dx;
98 }
99 y += dy;
100 }
101}
102
103GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
104 const GrSamplerState& sampler,
105 const GrGpu::TextureDesc& desc,
106 void* srcData, size_t rowBytes) {
107 GrAssert(key->width() == desc.fWidth);
108 GrAssert(key->height() == desc.fHeight);
109
110#if GR_DUMP_TEXTURE_UPLOAD
111 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
112#endif
113
114 GrTextureEntry* entry = NULL;
115 bool special = finalizeTextureKey(key, sampler);
116 if (special) {
117 GrTextureEntry* clampEntry;
118 GrTextureKey clampKey(*key);
119 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
120
121 if (NULL == clampEntry) {
122 clampEntry = createAndLockTexture(&clampKey,
123 GrSamplerState::ClampNoFilter(),
124 desc, srcData, rowBytes);
125 GrAssert(NULL != clampEntry);
126 if (NULL == clampEntry) {
127 return NULL;
128 }
129 }
130 GrTexture* clampTexture = clampEntry->texture();
131 GrGpu::TextureDesc rtDesc = desc;
132 rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag |
133 GrGpu::kNoPathRendering_TextureFlag;
134 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
135 fGpu->minRenderTargetWidth()));
136 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
137 fGpu->minRenderTargetHeight()));
138
139 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
140
141 if (NULL != texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000142 GrDrawTarget::AutoStateRestore asr(fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000143 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000144 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000145 fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000146 fGpu->setTextureMatrix(0, GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000147 fGpu->setViewMatrix(GrMatrix::I());
148 fGpu->setAlpha(0xff);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000149 fGpu->setBlendFunc(GrDrawTarget::kOne_BlendCoeff, GrDrawTarget::kZero_BlendCoeff);
150 fGpu->disableState(GrDrawTarget::kDither_StateBit |
151 GrDrawTarget::kClip_StateBit |
152 GrDrawTarget::kAntialias_StateBit);
reed@google.comac10a2d2010-12-22 21:39:39 +0000153 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
154 GrSamplerState::kClamp_WrapMode,
155 sampler.isFilter());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000156 fGpu->setSamplerState(0, stretchSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000157
158 static const GrVertexLayout layout =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000159 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000160 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
161
162 if (arg.succeeded()) {
163 GrPoint* verts = (GrPoint*) arg.vertices();
164 verts[0].setIRectFan(0, 0,
165 texture->contentWidth(),
166 texture->contentHeight(),
167 2*sizeof(GrPoint));
168 GrScalar tw = GrFixedToScalar(GR_Fixed1 *
169 clampTexture->contentWidth() /
170 clampTexture->allocWidth());
171 GrScalar th = GrFixedToScalar(GR_Fixed1 *
172 clampTexture->contentHeight() /
173 clampTexture->allocHeight());
174 verts[1].setRectFan(0, 0, tw, th, 2*sizeof(GrPoint));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000175 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000176 0, 4);
177 entry = fTextureCache->createAndLock(*key, texture);
178 }
179 texture->removeRenderTarget();
180 } else {
181 // TODO: Our CPU stretch doesn't filter. But we create separate
182 // stretched textures when the sampler state is either filtered or
183 // not. Either implement filtered stretch blit on CPU or just create
184 // one when FBO case fails.
185
186 rtDesc.fFlags = 0;
187 // no longer need to clamp at min RT size.
188 rtDesc.fWidth = GrNextPow2(desc.fWidth);
189 rtDesc.fHeight = GrNextPow2(desc.fHeight);
190 int bpp = GrTexture::BytesPerPixel(desc.fFormat);
191 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
192 rtDesc.fWidth *
193 rtDesc.fHeight);
194 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
195 srcData, desc.fWidth, desc.fHeight, bpp);
196
197 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
198
199 GrTexture* texture = fGpu->createTexture(rtDesc,
200 stretchedPixels.get(),
201 stretchedRowBytes);
202 GrAssert(NULL != texture);
203 entry = fTextureCache->createAndLock(*key, texture);
204 }
205 fTextureCache->unlock(clampEntry);
206
207 } else {
208 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
209 if (NULL != texture) {
210 entry = fTextureCache->createAndLock(*key, texture);
211 } else {
212 entry = NULL;
213 }
214 }
215 return entry;
216}
217
218void GrContext::unlockTexture(GrTextureEntry* entry) {
219 fTextureCache->unlock(entry);
220}
221
222void GrContext::detachCachedTexture(GrTextureEntry* entry) {
223 fTextureCache->detach(entry);
224}
225
226void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) {
227 fTextureCache->reattachAndUnlock(entry);
228}
229
230GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc,
231 void* srcData,
232 size_t rowBytes) {
233 return fGpu->createTexture(desc, srcData, rowBytes);
234}
235
reed@google.com01804b42011-01-18 21:50:41 +0000236void GrContext::getTextureCacheLimits(int* maxTextures,
237 size_t* maxTextureBytes) const {
238 fTextureCache->getLimits(maxTextures, maxTextureBytes);
239}
240
241void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
242 fTextureCache->setLimits(maxTextures, maxTextureBytes);
243}
244
reed@google.com02a7e6c2011-01-28 21:21:49 +0000245int GrContext::getMaxTextureDimension() {
246 return fGpu->maxTextureDimension();
247}
248
reed@google.com01804b42011-01-18 21:50:41 +0000249///////////////////////////////////////////////////////////////////////////////
250
reed@google.comac10a2d2010-12-22 21:39:39 +0000251GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,
252 int width, int height) {
253 return fGpu->createPlatformRenderTarget(platformRenderTarget,
254 width, height);
255}
256
257bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
258 int width, int height) {
259 if (!fGpu->supports8BitPalette()) {
260 return false;
261 }
262
bsalomon@google.com0748f212011-02-01 22:56:16 +0000263
reed@google.comac10a2d2010-12-22 21:39:39 +0000264 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
265
bsalomon@google.com0748f212011-02-01 22:56:16 +0000266 if (!isPow2) {
267 if (!fGpu->npotTextureSupport()) {
268 return false;
269 }
270
271 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
272 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
273 if (tiled && !fGpu->npotTextureTileSupport()) {
274 return false;
275 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000276 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000277 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000278}
279
280////////////////////////////////////////////////////////////////////////////////
281
bsalomon@google.com5782d712011-01-21 21:03:59 +0000282void GrContext::setClip(const GrClip& clip) {
283 fGpu->setClip(clip);
284 fGpu->enableState(GrDrawTarget::kClip_StateBit);
285}
286
287void GrContext::setClip(const GrIRect& rect) {
288 GrClip clip;
289 clip.setRect(rect);
290 fGpu->setClip(clip);
291}
292
293////////////////////////////////////////////////////////////////////////////////
294
reed@google.comac10a2d2010-12-22 21:39:39 +0000295void GrContext::eraseColor(GrColor color) {
296 fGpu->eraseColor(color);
297}
298
bsalomon@google.com5782d712011-01-21 21:03:59 +0000299void GrContext::drawPaint(const GrPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000300 // set rect to be big enough to fill the space, but not super-huge, so we
301 // don't overflow fixed-point implementations
302 GrRect r(fGpu->getClip().getBounds());
303 GrMatrix inverse;
304 if (fGpu->getViewInverse(&inverse)) {
305 inverse.mapRect(&r);
306 } else {
307 GrPrintf("---- fGpu->getViewInverse failed\n");
308 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000309 this->drawRect(paint, r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000310}
311
312/* create a triangle strip that strokes the specified triangle. There are 8
313 unique vertices, but we repreat the last 2 to close up. Alternatively we
314 could use an indices array, and then only send 8 verts, but not sure that
315 would be faster.
316 */
317static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
318 GrScalar width) {
319 const GrScalar rad = GrScalarHalf(width);
320
321 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
322 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
323 verts[2].set(rect.fRight - rad, rect.fTop + rad);
324 verts[3].set(rect.fRight + rad, rect.fTop - rad);
325 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
326 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
327 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
328 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
329 verts[8] = verts[0];
330 verts[9] = verts[1];
331}
332
bsalomon@google.com5782d712011-01-21 21:03:59 +0000333void GrContext::drawRect(const GrPaint& paint,
334 const GrRect& rect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000335 GrScalar width,
336 const GrMatrix* matrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000337
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000338 bool textured = NULL != paint.getTexture();
339 GrVertexLayout layout = (textured) ?
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000340 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
reed@google.comac10a2d2010-12-22 21:39:39 +0000341 0;
342
bsalomon@google.com5782d712011-01-21 21:03:59 +0000343 this->prepareToDraw(paint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000344
reed@google.comac10a2d2010-12-22 21:39:39 +0000345 if (width >= 0) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000346 // TODO: consider making static vertex buffers for these cases.
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000347 // Hairline could be done by just adding closing vertex to
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000348 // unitSquareVertexBuffer()
349 static const int worstCaseVertCount = 10;
350 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, worstCaseVertCount, 0);
351
352 if (!geo.succeeded()) {
353 return;
354 }
355
356 GrDrawTarget::PrimitiveType primType;
357 int vertCount;
358 GrPoint* vertex = geo.positions();
359
reed@google.comac10a2d2010-12-22 21:39:39 +0000360 if (width > 0) {
361 vertCount = 10;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000362 primType = GrDrawTarget::kTriangleStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000363 setStrokeRectStrip(vertex, rect, width);
364 } else {
365 // hairline
366 vertCount = 5;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000367 primType = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000368 vertex[0].set(rect.fLeft, rect.fTop);
369 vertex[1].set(rect.fRight, rect.fTop);
370 vertex[2].set(rect.fRight, rect.fBottom);
371 vertex[3].set(rect.fLeft, rect.fBottom);
372 vertex[4].set(rect.fLeft, rect.fTop);
373 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000374
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000375 GrDrawTarget::AutoViewMatrixRestore avmr;
376 if (NULL != matrix) {
377 avmr.set(fGpu);
378 fGpu->concatViewMatrix(*matrix);
379 fGpu->concatTextureMatrix(0, *matrix);
380 }
381
382 fGpu->drawNonIndexed(primType, 0, vertCount);
383 } else {
bsalomon@google.com43333232011-02-02 19:24:54 +0000384 #if GR_STATIC_RECT_VB
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000385 fGpu->setVertexSourceToBuffer(fGpu->unitSquareVertexBuffer(), layout);
386 GrDrawTarget::AutoViewMatrixRestore avmr(fGpu);
387 GrMatrix m;
388 m.setAll(rect.width(), 0, rect.fLeft,
389 0, rect.height(), rect.fTop,
390 0, 0, GrMatrix::I()[8]);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000391
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000392 if (NULL != matrix) {
393 m.postConcat(*matrix);
394 }
395
396 fGpu->concatViewMatrix(m);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000397
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000398 if (textured) {
399 fGpu->concatTextureMatrix(0, m);
400 }
401 #else
402 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, 4, 0);
403 GrPoint* vertex = geo.positions();
404 vertex->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
405
406 GrDrawTarget::AutoViewMatrixRestore avmr;
407 if (NULL != matrix) {
408 avmr.set(fGpu);
409 fGpu->concatViewMatrix(*matrix);
410 fGpu->concatTextureMatrix(0, *matrix);
411 }
412 #endif
413
414 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
415 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000416}
417
bsalomon@google.com5782d712011-01-21 21:03:59 +0000418void GrContext::drawRectToRect(const GrPaint& paint,
419 const GrRect& dstRect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000420 const GrRect& srcRect,
421 const GrMatrix* dstMatrix,
422 const GrMatrix* srcMatrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000423
424 if (NULL == paint.getTexture()) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000425 drawRect(paint, dstRect, -1, dstMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000426 return;
427 }
428
429 this->prepareToDraw(paint);
430
bsalomon@google.com43333232011-02-02 19:24:54 +0000431#if GR_STATIC_RECT_VB
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000432 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
433 GrDrawTarget::AutoViewMatrixRestore avmr(fGpu);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000434
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000435 GrMatrix m;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000436
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000437 m.setAll(dstRect.width(), 0, dstRect.fLeft,
438 0, dstRect.height(), dstRect.fTop,
439 0, 0, GrMatrix::I()[8]);
440 if (NULL != dstMatrix) {
441 m.postConcat(*dstMatrix);
442 }
443 fGpu->concatViewMatrix(m);
444
445 m.setAll(srcRect.width(), 0, srcRect.fLeft,
446 0, srcRect.height(), srcRect.fTop,
447 0, 0, GrMatrix::I()[8]);
448 if (NULL != srcMatrix) {
449 m.postConcat(*srcMatrix);
450 }
451 fGpu->concatTextureMatrix(0, m);
452
453 fGpu->setVertexSourceToBuffer(fGpu->unitSquareVertexBuffer(), layout);
454#else
455 GrVertexLayout layout = GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
456
457 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, 4, 0);
458 GrPoint* pos = geo.positions();
459 GrPoint* tex = pos + 1;
460 static const size_t stride = 2 * sizeof(GrPoint);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000461 pos[0].setRectFan(dstRect.fLeft, dstRect.fTop,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000462 dstRect.fRight, dstRect.fBottom,
463 stride);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000464 tex[0].setRectFan(srcRect.fLeft, srcRect.fTop,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000465 srcRect.fRight, srcRect.fBottom,
466 stride);
467
468 GrDrawTarget::AutoViewMatrixRestore avmr;
469 if (NULL != dstMatrix) {
470 avmr.set(fGpu);
471 fGpu->concatViewMatrix(*dstMatrix);
472 }
473 if (NULL != srcMatrix) {
474 fGpu->concatTextureMatrix(0, *srcMatrix);
475 }
476
477#endif
478 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000479}
480
481void GrContext::drawVertices(const GrPaint& paint,
482 GrDrawTarget::PrimitiveType primitiveType,
483 int vertexCount,
484 const GrPoint positions[],
485 const GrPoint texCoords[],
486 const GrColor colors[],
487 const uint16_t indices[],
488 int indexCount) {
489 GrVertexLayout layout = 0;
490 bool interLeave = false;
491
492 GrDrawTarget::AutoReleaseGeometry geo;
493
494 this->prepareToDraw(paint);
495
496 if (NULL != paint.getTexture()) {
497 if (NULL == texCoords) {
498 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
499 } else {
500 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
501 interLeave = true;
502 }
503 }
504
505 if (NULL != colors) {
506 layout |= GrDrawTarget::kColor_VertexLayoutBit;
507 }
508
509 static const GrVertexLayout interleaveMask =
510 (GrDrawTarget::StageTexCoordVertexLayoutBit(0,0) |
511 GrDrawTarget::kColor_VertexLayoutBit);
512 if (interleaveMask & layout) {
513 if (!geo.set(fGpu, layout, vertexCount, 0)) {
514 GrPrintf("Failed to get space for vertices!");
515 return;
516 }
517 int texOffsets[GrDrawTarget::kMaxTexCoords];
518 int colorOffset;
519 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
520 texOffsets,
521 &colorOffset);
522 void* curVertex = geo.vertices();
523
524 for (int i = 0; i < vertexCount; ++i) {
525 *((GrPoint*)curVertex) = positions[i];
526
527 if (texOffsets[0] > 0) {
528 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
529 }
530 if (colorOffset > 0) {
531 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
532 }
533 curVertex = (void*)((intptr_t)curVertex + vsize);
534 }
535 } else {
536 fGpu->setVertexSourceToArray(positions, layout);
537 }
538
539 if (NULL != indices) {
540 fGpu->setIndexSourceToArray(indices);
541 fGpu->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
542 } else {
543 fGpu->drawNonIndexed(primitiveType, 0, vertexCount);
544 }
545}
546
547
reed@google.comac10a2d2010-12-22 21:39:39 +0000548////////////////////////////////////////////////////////////////////////////////
549
reed@google.comac10a2d2010-12-22 21:39:39 +0000550#define STENCIL_OFF 0 // Always disable stencil (even when needed)
reed@google.comac10a2d2010-12-22 21:39:39 +0000551#define EVAL_TOL GR_Scalar1
552
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000553static const uint32_t MAX_POINTS_PER_CURVE = 1 << 10;
554
reed@google.comac10a2d2010-12-22 21:39:39 +0000555static uint32_t quadratic_point_count(const GrPoint points[], GrScalar tol) {
556 GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
557 // TODO: fixed points sqrt
558 if (d < tol) {
559 return 1;
560 } else {
561 // Each time we subdivide, d should be cut in 4. So we need to
562 // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
563 // points.
564 // 2^(log4(x)) = sqrt(x);
565 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000566 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000567 }
568}
569
570static uint32_t generate_quadratic_points(const GrPoint& p0,
571 const GrPoint& p1,
572 const GrPoint& p2,
573 GrScalar tolSqd,
574 GrPoint** points,
575 uint32_t pointsLeft) {
576 if (pointsLeft < 2 ||
577 (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
578 (*points)[0] = p2;
579 *points += 1;
580 return 1;
581 }
582
583 GrPoint q[] = {
584 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
585 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
586 };
587 GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY));
588
589 pointsLeft >>= 1;
590 uint32_t a = generate_quadratic_points(p0, q[0], r, tolSqd, points, pointsLeft);
591 uint32_t b = generate_quadratic_points(r, q[1], p2, tolSqd, points, pointsLeft);
592 return a + b;
593}
594
595static uint32_t cubic_point_count(const GrPoint points[], GrScalar tol) {
596 GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
597 points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
598 d = sqrtf(d);
599 if (d < tol) {
600 return 1;
601 } else {
602 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000603 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000604 }
605}
606
607static uint32_t generate_cubic_points(const GrPoint& p0,
608 const GrPoint& p1,
609 const GrPoint& p2,
610 const GrPoint& p3,
611 GrScalar tolSqd,
612 GrPoint** points,
613 uint32_t pointsLeft) {
614 if (pointsLeft < 2 ||
615 (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
616 p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
617 (*points)[0] = p3;
618 *points += 1;
619 return 1;
620 }
621 GrPoint q[] = {
622 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
623 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
624 GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY))
625 };
626 GrPoint r[] = {
627 GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)),
628 GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY))
629 };
630 GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY));
631 pointsLeft >>= 1;
632 uint32_t a = generate_cubic_points(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
633 uint32_t b = generate_cubic_points(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
634 return a + b;
635}
636
reed@google.comac10a2d2010-12-22 21:39:39 +0000637static int worst_case_point_count(GrPathIter* path,
638 int* subpaths,
reed@google.comac10a2d2010-12-22 21:39:39 +0000639 GrScalar tol) {
640 int pointCount = 0;
641 *subpaths = 1;
642
643 bool first = true;
644
645 GrPathIter::Command cmd;
646
647 GrPoint pts[4];
648 while ((cmd = path->next(pts)) != GrPathIter::kEnd_Command) {
649
650 switch (cmd) {
651 case GrPathIter::kLine_Command:
652 pointCount += 1;
653 break;
654 case GrPathIter::kQuadratic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000655 pointCount += quadratic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000656 break;
657 case GrPathIter::kCubic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000658 pointCount += cubic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000659 break;
660 case GrPathIter::kMove_Command:
661 pointCount += 1;
662 if (!first) {
663 ++(*subpaths);
664 }
665 break;
666 default:
667 break;
668 }
669 first = false;
670 }
671 return pointCount;
672}
673
674static inline bool single_pass_path(const GrPathIter& path,
675 GrContext::PathFills fill,
reed@google.comac10a2d2010-12-22 21:39:39 +0000676 const GrGpu& gpu) {
677#if STENCIL_OFF
678 return true;
679#else
680 if (GrContext::kEvenOdd_PathFill == fill) {
681 GrPathIter::ConvexHint hint = path.hint();
682 return hint == GrPathIter::kConvex_ConvexHint ||
683 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint;
684 } else if (GrContext::kWinding_PathFill == fill) {
685 GrPathIter::ConvexHint hint = path.hint();
686 return hint == GrPathIter::kConvex_ConvexHint ||
687 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint ||
688 (hint == GrPathIter::kSameWindingConvexPieces_ConvexHint &&
689 gpu.canDisableBlend() && !gpu.isDitherState());
690
691 }
692 return false;
693#endif
694}
695
bsalomon@google.com5782d712011-01-21 21:03:59 +0000696void GrContext::drawPath(const GrPaint& paint,
697 GrPathIter* path,
698 PathFills fill,
699 const GrPoint* translate) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000700
reed@google.comac10a2d2010-12-22 21:39:39 +0000701
bsalomon@google.com5782d712011-01-21 21:03:59 +0000702 this->prepareToDraw(paint);
703
704 GrDrawTarget::AutoStateRestore asr(fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000705
bsalomon@google.com5782d712011-01-21 21:03:59 +0000706 GrMatrix viewM = fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000707 // In order to tesselate the path we get a bound on how much the matrix can
708 // stretch when mapping to screen coordinates.
709 GrScalar stretch = viewM.getMaxStretch();
710 bool useStretch = stretch > 0;
711 GrScalar tol = EVAL_TOL;
712 if (!useStretch) {
713 // TODO: deal with perspective in some better way.
714 tol /= 10;
715 } else {
716 // TODO: fixed point divide
717 GrScalar sinv = 1 / stretch;
718 tol = GrMul(tol, sinv);
reed@google.comac10a2d2010-12-22 21:39:39 +0000719 }
720 GrScalar tolSqd = GrMul(tol, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000721
722 int subpathCnt;
723 int maxPts = worst_case_point_count(path,
724 &subpathCnt,
reed@google.comac10a2d2010-12-22 21:39:39 +0000725 tol);
726 GrVertexLayout layout = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000727
728 if (NULL != paint.getTexture()) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000729 layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000730 }
731 // add 4 to hold the bounding rect
732 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, maxPts + 4, 0);
733
734 GrPoint* base = (GrPoint*) arg.vertices();
735 GrPoint* vert = base;
736 GrPoint* subpathBase = base;
737
738 GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
739
740 path->rewind();
741
742 // TODO: use primitve restart if available rather than multiple draws
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000743 GrDrawTarget::PrimitiveType type;
744 int passCount = 0;
745 GrDrawTarget::StencilPass passes[3];
746 bool reverse = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000747
748 if (kHairLine_PathFill == fill) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000749 type = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000750 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000751 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000752 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000753 type = GrDrawTarget::kTriangleFan_PrimitiveType;
754 if (single_pass_path(*path, fill, *fGpu)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000755 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000756 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000757 } else {
758 switch (fill) {
759 case kInverseEvenOdd_PathFill:
760 reverse = true;
761 // fallthrough
762 case kEvenOdd_PathFill:
763 passCount = 2;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000764 passes[0] = GrDrawTarget::kEvenOddStencil_StencilPass;
765 passes[1] = GrDrawTarget::kEvenOddColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000766 break;
767
768 case kInverseWinding_PathFill:
769 reverse = true;
770 // fallthrough
771 case kWinding_PathFill:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000772 passes[0] = GrDrawTarget::kWindingStencil1_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000773 if (fGpu->supportsSingleStencilPassWinding()) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000774 passes[1] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000775 passCount = 2;
776 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000777 passes[1] = GrDrawTarget::kWindingStencil2_StencilPass;
778 passes[2] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000779 passCount = 3;
780 }
781 break;
782 default:
783 GrAssert(!"Unknown path fill!");
784 return;
785 }
786 }
787 }
788 fGpu->setReverseFill(reverse);
reed@google.comac10a2d2010-12-22 21:39:39 +0000789
790 GrPoint pts[4];
791
792 bool first = true;
793 int subpath = 0;
794
795 for (;;) {
796 GrPathIter::Command cmd = path->next(pts);
reed@google.comac10a2d2010-12-22 21:39:39 +0000797 switch (cmd) {
798 case GrPathIter::kMove_Command:
799 if (!first) {
800 subpathVertCount[subpath] = vert-subpathBase;
801 subpathBase = vert;
802 ++subpath;
803 }
804 *vert = pts[0];
805 vert++;
806 break;
807 case GrPathIter::kLine_Command:
808 *vert = pts[1];
809 vert++;
810 break;
811 case GrPathIter::kQuadratic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000812 generate_quadratic_points(pts[0], pts[1], pts[2],
813 tolSqd, &vert,
814 quadratic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000815 break;
816 }
817 case GrPathIter::kCubic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000818 generate_cubic_points(pts[0], pts[1], pts[2], pts[3],
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000819 tolSqd, &vert,
reed@google.comac10a2d2010-12-22 21:39:39 +0000820 cubic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000821 break;
822 }
823 case GrPathIter::kClose_Command:
824 break;
825 case GrPathIter::kEnd_Command:
826 subpathVertCount[subpath] = vert-subpathBase;
827 ++subpath; // this could be only in debug
828 goto FINISHED;
829 }
830 first = false;
831 }
832FINISHED:
833 GrAssert(subpath == subpathCnt);
834 GrAssert((vert - base) <= maxPts);
835
836 if (translate) {
837 int count = vert - base;
838 for (int i = 0; i < count; i++) {
839 base[i].offset(translate->fX, translate->fY);
840 }
841 }
842
843 // arbitrary path complexity cutoff
844 bool useBounds = fill != kHairLine_PathFill &&
845 (reverse || (vert - base) > 8);
846 GrPoint* boundsVerts = base + maxPts;
847 if (useBounds) {
848 GrRect bounds;
849 if (reverse) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000850 GrAssert(NULL != fGpu->getRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000851 // draw over the whole world.
852 bounds.setLTRB(0, 0,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000853 GrIntToScalar(fGpu->getRenderTarget()->width()),
854 GrIntToScalar(fGpu->getRenderTarget()->height()));
855 GrMatrix vmi;
856 if (fGpu->getViewInverse(&vmi)) {
857 vmi.mapRect(&bounds);
858 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 } else {
860 bounds.setBounds((GrPoint*)base, vert - base);
861 }
862 boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
863 bounds.fBottom);
864 }
865
866 for (int p = 0; p < passCount; ++p) {
867 fGpu->setStencilPass(passes[p]);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000868 if (useBounds && (GrDrawTarget::kEvenOddColor_StencilPass == passes[p] ||
869 GrDrawTarget::kWindingColor_StencilPass == passes[p])) {
870 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000871 maxPts, 4);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000872
reed@google.comac10a2d2010-12-22 21:39:39 +0000873 } else {
874 int baseVertex = 0;
875 for (int sp = 0; sp < subpathCnt; ++sp) {
876 fGpu->drawNonIndexed(type,
877 baseVertex,
878 subpathVertCount[sp]);
879 baseVertex += subpathVertCount[sp];
880 }
881 }
882 }
883}
884
bsalomon@google.com5782d712011-01-21 21:03:59 +0000885////////////////////////////////////////////////////////////////////////////////
886
reed@google.comac10a2d2010-12-22 21:39:39 +0000887void GrContext::flush(bool flushRenderTarget) {
888 flushText();
889 if (flushRenderTarget) {
890 fGpu->forceRenderTargetFlush();
891 }
892}
893
894void GrContext::flushText() {
895 fTextDrawBuffer.playback(fGpu);
896 fTextDrawBuffer.reset();
897}
898
899bool GrContext::readPixels(int left, int top, int width, int height,
900 GrTexture::PixelConfig config, void* buffer) {
901 this->flush(true);
902 return fGpu->readPixels(left, top, width, height, config, buffer);
903}
904
905void GrContext::writePixels(int left, int top, int width, int height,
906 GrTexture::PixelConfig config, const void* buffer,
907 size_t stride) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000908
909 // TODO: when underlying api has a direct way to do this we should use it
910 // (e.g. glDrawPixels on desktop GL).
911
reed@google.comac10a2d2010-12-22 21:39:39 +0000912 const GrGpu::TextureDesc desc = {
913 0, GrGpu::kNone_AALevel, width, height, config
914 };
915 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
916 if (NULL == texture) {
917 return;
918 }
919
920 this->flush(true);
921
922 GrAutoUnref aur(texture);
923 GrDrawTarget::AutoStateRestore asr(fGpu);
924
925 GrMatrix matrix;
926 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
927 fGpu->setViewMatrix(matrix);
928 matrix.setScale(GR_Scalar1 / texture->allocWidth(),
929 GR_Scalar1 / texture->allocHeight());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000930 fGpu->setTextureMatrix(0, matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000931
932 fGpu->disableState(GrDrawTarget::kClip_StateBit);
933 fGpu->setAlpha(0xFF);
934 fGpu->setBlendFunc(GrDrawTarget::kOne_BlendCoeff,
935 GrDrawTarget::kZero_BlendCoeff);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000936 fGpu->setTexture(0, texture);
937 fGpu->setSamplerState(0, GrSamplerState::ClampNoFilter());
reed@google.comac10a2d2010-12-22 21:39:39 +0000938
bsalomon@google.com5782d712011-01-21 21:03:59 +0000939 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
940 static const int VCOUNT = 4;
941
942 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
943 if (!geo.succeeded()) {
944 return;
945 }
946 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
947 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, VCOUNT);
948}
949////////////////////////////////////////////////////////////////////////////////
950
951void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
952 target->setTexture(0, paint.getTexture());
953 target->setTextureMatrix(0, paint.fTextureMatrix);
954 target->setSamplerState(0, paint.fSampler);
955 target->setColor(paint.fColor);
956
957 if (paint.fDither) {
958 target->enableState(GrDrawTarget::kDither_StateBit);
959 } else {
960 target->disableState(GrDrawTarget::kDither_StateBit);
961 }
962 if (paint.fAntiAlias) {
963 target->enableState(GrDrawTarget::kAntialias_StateBit);
964 } else {
965 target->disableState(GrDrawTarget::kAntialias_StateBit);
966 }
967 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
968}
969
970void GrContext::prepareToDraw(const GrPaint& paint) {
971
972 flushText();
973 SetPaint(paint, fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000974}
975
976////////////////////////////////////////////////////////////////////////////////
977
reed@google.comac10a2d2010-12-22 21:39:39 +0000978void GrContext::resetContext() {
979 fGpu->resetContext();
980}
981
reed@google.comac10a2d2010-12-22 21:39:39 +0000982void GrContext::setRenderTarget(GrRenderTarget* target) {
983 flushText();
984 fGpu->setRenderTarget(target);
985}
986
bsalomon@google.com5782d712011-01-21 21:03:59 +0000987GrRenderTarget* GrContext::getRenderTarget() {
988 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +0000989}
990
bsalomon@google.com5782d712011-01-21 21:03:59 +0000991const GrRenderTarget* GrContext::getRenderTarget() const {
992 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +0000993}
994
bsalomon@google.com5782d712011-01-21 21:03:59 +0000995const GrMatrix& GrContext::getMatrix() const {
996 return fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000997}
998
bsalomon@google.com5782d712011-01-21 21:03:59 +0000999void GrContext::setMatrix(const GrMatrix& m) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001000 fGpu->setViewMatrix(m);
1001}
1002
bsalomon@google.com5782d712011-01-21 21:03:59 +00001003void GrContext::concatMatrix(const GrMatrix& m) const {
1004 fGpu->concatViewMatrix(m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001005}
1006
1007static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1008 intptr_t mask = 1 << shift;
1009 if (pred) {
1010 bits |= mask;
1011 } else {
1012 bits &= ~mask;
1013 }
1014 return bits;
1015}
1016
reed@google.comac10a2d2010-12-22 21:39:39 +00001017void GrContext::resetStats() {
1018 fGpu->resetStats();
1019}
1020
1021const GrGpu::Stats& GrContext::getStats() const {
1022 return fGpu->getStats();
1023}
1024
1025void GrContext::printStats() const {
1026 fGpu->printStats();
1027}
1028
1029GrContext::GrContext(GrGpu* gpu) :
1030 fVBAllocPool(gpu,
1031 gpu->supportsBufferLocking() ? POOL_VB_SIZE : 0,
1032 gpu->supportsBufferLocking() ? NUM_POOL_VBS : 0),
1033 fTextDrawBuffer(gpu->supportsBufferLocking() ? &fVBAllocPool : NULL) {
1034 fGpu = gpu;
1035 fGpu->ref();
1036 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1037 MAX_TEXTURE_CACHE_BYTES);
1038 fFontCache = new GrFontCache(fGpu);
1039}
1040
1041bool GrContext::finalizeTextureKey(GrTextureKey* key,
1042 const GrSamplerState& sampler) const {
1043 uint32_t bits = 0;
1044 uint16_t width = key->width();
1045 uint16_t height = key->height();
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001046
bsalomon@google.com0748f212011-02-01 22:56:16 +00001047
1048 if (!fGpu->npotTextureTileSupport()) {
1049 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
1050
1051 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
1052 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
1053
1054 if (tiled && !isPow2) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001055 bits |= 1;
1056 bits |= sampler.isFilter() ? 2 : 0;
1057 }
1058 }
1059 key->finalize(bits);
1060 return 0 != bits;
1061}
1062
bsalomon@google.com5782d712011-01-21 21:03:59 +00001063GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1064 GrDrawTarget* target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001065#if DEFER_TEXT_RENDERING
1066 fTextDrawBuffer.initializeDrawStateAndClip(*fGpu);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001067 target = &fTextDrawBuffer;
reed@google.comac10a2d2010-12-22 21:39:39 +00001068#else
bsalomon@google.com5782d712011-01-21 21:03:59 +00001069 target = fGpu;
reed@google.comac10a2d2010-12-22 21:39:39 +00001070#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +00001071 SetPaint(paint, target);
1072 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001073}
1074
1075const GrIndexBuffer* GrContext::quadIndexBuffer() const {
1076 return fGpu->quadIndexBuffer();
1077}
1078
1079int GrContext::maxQuadsInIndexBuffer() const {
1080 return fGpu->maxQuadsInIndexBuffer();
1081}
1082
1083
1084