blob: bcccc4e22090ec29cd378dea0a48ab0776461e9c [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"
19#include "GrTextureCache.h"
20#include "GrTextStrike.h"
21#include "GrMemory.h"
22#include "GrPathIter.h"
23#include "GrClipIterator.h"
24#include "GrIndexBuffer.h"
25
26#define DEFER_TEXT_RENDERING 1
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +000027#define USE_STATIC_RECT_VB 0
reed@google.comac10a2d2010-12-22 21:39:39 +000028
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
263 bool needsRepeat = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
264 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
265 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
266
267 switch (fGpu->npotTextureSupport()) {
268 case GrGpu::kNone_NPOTTextureType:
269 return isPow2;
270 case GrGpu::kNoRepeat_NPOTTextureType:
271 return isPow2 || !needsRepeat;
272 case GrGpu::kNonRendertarget_NPOTTextureType:
273 case GrGpu::kFull_NPOTTextureType:
274 return true;
275 }
276 // should never get here
277 GrAssert(!"Bad enum from fGpu->npotTextureSupport");
278 return false;
279}
280
281////////////////////////////////////////////////////////////////////////////////
282
bsalomon@google.com5782d712011-01-21 21:03:59 +0000283void GrContext::setClip(const GrClip& clip) {
284 fGpu->setClip(clip);
285 fGpu->enableState(GrDrawTarget::kClip_StateBit);
286}
287
288void GrContext::setClip(const GrIRect& rect) {
289 GrClip clip;
290 clip.setRect(rect);
291 fGpu->setClip(clip);
292}
293
294////////////////////////////////////////////////////////////////////////////////
295
reed@google.comac10a2d2010-12-22 21:39:39 +0000296void GrContext::eraseColor(GrColor color) {
297 fGpu->eraseColor(color);
298}
299
bsalomon@google.com5782d712011-01-21 21:03:59 +0000300void GrContext::drawPaint(const GrPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000301 // set rect to be big enough to fill the space, but not super-huge, so we
302 // don't overflow fixed-point implementations
303 GrRect r(fGpu->getClip().getBounds());
304 GrMatrix inverse;
305 if (fGpu->getViewInverse(&inverse)) {
306 inverse.mapRect(&r);
307 } else {
308 GrPrintf("---- fGpu->getViewInverse failed\n");
309 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000310 this->drawRect(paint, r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000311}
312
313/* create a triangle strip that strokes the specified triangle. There are 8
314 unique vertices, but we repreat the last 2 to close up. Alternatively we
315 could use an indices array, and then only send 8 verts, but not sure that
316 would be faster.
317 */
318static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
319 GrScalar width) {
320 const GrScalar rad = GrScalarHalf(width);
321
322 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
323 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
324 verts[2].set(rect.fRight - rad, rect.fTop + rad);
325 verts[3].set(rect.fRight + rad, rect.fTop - rad);
326 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
327 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
328 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
329 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
330 verts[8] = verts[0];
331 verts[9] = verts[1];
332}
333
bsalomon@google.com5782d712011-01-21 21:03:59 +0000334void GrContext::drawRect(const GrPaint& paint,
335 const GrRect& rect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000336 GrScalar width,
337 const GrMatrix* matrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000338
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000339 bool textured = NULL != paint.getTexture();
340 GrVertexLayout layout = (textured) ?
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000341 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
reed@google.comac10a2d2010-12-22 21:39:39 +0000342 0;
343
bsalomon@google.com5782d712011-01-21 21:03:59 +0000344 this->prepareToDraw(paint);
reed@google.comac10a2d2010-12-22 21:39:39 +0000345
reed@google.comac10a2d2010-12-22 21:39:39 +0000346 if (width >= 0) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000347 // TODO: consider making static vertex buffers for these cases.
348 // Hairline could be done by just adding closing vertex to
349 // unitSquareVertexBuffer()
350 static const int worstCaseVertCount = 10;
351 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, worstCaseVertCount, 0);
352
353 if (!geo.succeeded()) {
354 return;
355 }
356
357 GrDrawTarget::PrimitiveType primType;
358 int vertCount;
359 GrPoint* vertex = geo.positions();
360
reed@google.comac10a2d2010-12-22 21:39:39 +0000361 if (width > 0) {
362 vertCount = 10;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000363 primType = GrDrawTarget::kTriangleStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000364 setStrokeRectStrip(vertex, rect, width);
365 } else {
366 // hairline
367 vertCount = 5;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000368 primType = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000369 vertex[0].set(rect.fLeft, rect.fTop);
370 vertex[1].set(rect.fRight, rect.fTop);
371 vertex[2].set(rect.fRight, rect.fBottom);
372 vertex[3].set(rect.fLeft, rect.fBottom);
373 vertex[4].set(rect.fLeft, rect.fTop);
374 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000375
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000376 GrDrawTarget::AutoViewMatrixRestore avmr;
377 if (NULL != matrix) {
378 avmr.set(fGpu);
379 fGpu->concatViewMatrix(*matrix);
380 fGpu->concatTextureMatrix(0, *matrix);
381 }
382
383 fGpu->drawNonIndexed(primType, 0, vertCount);
384 } else {
385 #if USE_STATIC_RECT_VB
386 fGpu->setVertexSourceToBuffer(fGpu->unitSquareVertexBuffer(), layout);
387 GrDrawTarget::AutoViewMatrixRestore avmr(fGpu);
388 GrMatrix m;
389 m.setAll(rect.width(), 0, rect.fLeft,
390 0, rect.height(), rect.fTop,
391 0, 0, GrMatrix::I()[8]);
392
393 if (NULL != matrix) {
394 m.postConcat(*matrix);
395 }
396
397 fGpu->concatViewMatrix(m);
398
399 if (textured) {
400 fGpu->concatTextureMatrix(0, m);
401 }
402 #else
403 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, 4, 0);
404 GrPoint* vertex = geo.positions();
405 vertex->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
406
407 GrDrawTarget::AutoViewMatrixRestore avmr;
408 if (NULL != matrix) {
409 avmr.set(fGpu);
410 fGpu->concatViewMatrix(*matrix);
411 fGpu->concatTextureMatrix(0, *matrix);
412 }
413 #endif
414
415 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
416 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000417}
418
bsalomon@google.com5782d712011-01-21 21:03:59 +0000419void GrContext::drawRectToRect(const GrPaint& paint,
420 const GrRect& dstRect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000421 const GrRect& srcRect,
422 const GrMatrix* dstMatrix,
423 const GrMatrix* srcMatrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000424
425 if (NULL == paint.getTexture()) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000426 drawRect(paint, dstRect, -1, dstMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000427 return;
428 }
429
430 this->prepareToDraw(paint);
431
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000432#if USE_STATIC_RECT_VB
433 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
434 GrDrawTarget::AutoViewMatrixRestore avmr(fGpu);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000435
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000436 GrMatrix m;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000437
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000438 m.setAll(dstRect.width(), 0, dstRect.fLeft,
439 0, dstRect.height(), dstRect.fTop,
440 0, 0, GrMatrix::I()[8]);
441 if (NULL != dstMatrix) {
442 m.postConcat(*dstMatrix);
443 }
444 fGpu->concatViewMatrix(m);
445
446 m.setAll(srcRect.width(), 0, srcRect.fLeft,
447 0, srcRect.height(), srcRect.fTop,
448 0, 0, GrMatrix::I()[8]);
449 if (NULL != srcMatrix) {
450 m.postConcat(*srcMatrix);
451 }
452 fGpu->concatTextureMatrix(0, m);
453
454 fGpu->setVertexSourceToBuffer(fGpu->unitSquareVertexBuffer(), layout);
455#else
456 GrVertexLayout layout = GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
457
458 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, 4, 0);
459 GrPoint* pos = geo.positions();
460 GrPoint* tex = pos + 1;
461 static const size_t stride = 2 * sizeof(GrPoint);
462 pos[0].setRectFan(dstRect.fLeft, dstRect.fTop,
463 dstRect.fRight, dstRect.fBottom,
464 stride);
465 tex[0].setRectFan(srcRect.fLeft, srcRect.fTop,
466 srcRect.fRight, srcRect.fBottom,
467 stride);
468
469 GrDrawTarget::AutoViewMatrixRestore avmr;
470 if (NULL != dstMatrix) {
471 avmr.set(fGpu);
472 fGpu->concatViewMatrix(*dstMatrix);
473 }
474 if (NULL != srcMatrix) {
475 fGpu->concatTextureMatrix(0, *srcMatrix);
476 }
477
478#endif
479 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000480}
481
482void GrContext::drawVertices(const GrPaint& paint,
483 GrDrawTarget::PrimitiveType primitiveType,
484 int vertexCount,
485 const GrPoint positions[],
486 const GrPoint texCoords[],
487 const GrColor colors[],
488 const uint16_t indices[],
489 int indexCount) {
490 GrVertexLayout layout = 0;
491 bool interLeave = false;
492
493 GrDrawTarget::AutoReleaseGeometry geo;
494
495 this->prepareToDraw(paint);
496
497 if (NULL != paint.getTexture()) {
498 if (NULL == texCoords) {
499 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
500 } else {
501 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
502 interLeave = true;
503 }
504 }
505
506 if (NULL != colors) {
507 layout |= GrDrawTarget::kColor_VertexLayoutBit;
508 }
509
510 static const GrVertexLayout interleaveMask =
511 (GrDrawTarget::StageTexCoordVertexLayoutBit(0,0) |
512 GrDrawTarget::kColor_VertexLayoutBit);
513 if (interleaveMask & layout) {
514 if (!geo.set(fGpu, layout, vertexCount, 0)) {
515 GrPrintf("Failed to get space for vertices!");
516 return;
517 }
518 int texOffsets[GrDrawTarget::kMaxTexCoords];
519 int colorOffset;
520 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
521 texOffsets,
522 &colorOffset);
523 void* curVertex = geo.vertices();
524
525 for (int i = 0; i < vertexCount; ++i) {
526 *((GrPoint*)curVertex) = positions[i];
527
528 if (texOffsets[0] > 0) {
529 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
530 }
531 if (colorOffset > 0) {
532 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
533 }
534 curVertex = (void*)((intptr_t)curVertex + vsize);
535 }
536 } else {
537 fGpu->setVertexSourceToArray(positions, layout);
538 }
539
540 if (NULL != indices) {
541 fGpu->setIndexSourceToArray(indices);
542 fGpu->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
543 } else {
544 fGpu->drawNonIndexed(primitiveType, 0, vertexCount);
545 }
546}
547
548
reed@google.comac10a2d2010-12-22 21:39:39 +0000549////////////////////////////////////////////////////////////////////////////////
550
551#define NEW_EVAL 1 // Use adaptive path tesselation
552#define STENCIL_OFF 0 // Always disable stencil (even when needed)
553#define CPU_TRANSFORM 0 // Transform path verts on CPU
554
555#if NEW_EVAL
556
557#define EVAL_TOL GR_Scalar1
558
559static uint32_t quadratic_point_count(const GrPoint points[], GrScalar tol) {
560 GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
561 // TODO: fixed points sqrt
562 if (d < tol) {
563 return 1;
564 } else {
565 // Each time we subdivide, d should be cut in 4. So we need to
566 // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
567 // points.
568 // 2^(log4(x)) = sqrt(x);
569 d = ceilf(sqrtf(d/tol));
570 return GrNextPow2((uint32_t)d);
571 }
572}
573
574static uint32_t generate_quadratic_points(const GrPoint& p0,
575 const GrPoint& p1,
576 const GrPoint& p2,
577 GrScalar tolSqd,
578 GrPoint** points,
579 uint32_t pointsLeft) {
580 if (pointsLeft < 2 ||
581 (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
582 (*points)[0] = p2;
583 *points += 1;
584 return 1;
585 }
586
587 GrPoint q[] = {
588 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
589 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
590 };
591 GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY));
592
593 pointsLeft >>= 1;
594 uint32_t a = generate_quadratic_points(p0, q[0], r, tolSqd, points, pointsLeft);
595 uint32_t b = generate_quadratic_points(r, q[1], p2, tolSqd, points, pointsLeft);
596 return a + b;
597}
598
599static uint32_t cubic_point_count(const GrPoint points[], GrScalar tol) {
600 GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
601 points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
602 d = sqrtf(d);
603 if (d < tol) {
604 return 1;
605 } else {
606 d = ceilf(sqrtf(d/tol));
607 return GrNextPow2((uint32_t)d);
608 }
609}
610
611static uint32_t generate_cubic_points(const GrPoint& p0,
612 const GrPoint& p1,
613 const GrPoint& p2,
614 const GrPoint& p3,
615 GrScalar tolSqd,
616 GrPoint** points,
617 uint32_t pointsLeft) {
618 if (pointsLeft < 2 ||
619 (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
620 p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
621 (*points)[0] = p3;
622 *points += 1;
623 return 1;
624 }
625 GrPoint q[] = {
626 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
627 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
628 GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY))
629 };
630 GrPoint r[] = {
631 GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)),
632 GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY))
633 };
634 GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY));
635 pointsLeft >>= 1;
636 uint32_t a = generate_cubic_points(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
637 uint32_t b = generate_cubic_points(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
638 return a + b;
639}
640
641#else // !NEW_EVAL
642
643static GrScalar gr_eval_quad(const GrScalar coord[], GrScalar t) {
644 GrScalar A = coord[0] - 2 * coord[2] + coord[4];
645 GrScalar B = 2 * (coord[2] - coord[0]);
646 GrScalar C = coord[0];
647
648 return GrMul(GrMul(A, t) + B, t) + C;
649}
650
651static void gr_eval_quad_at(const GrPoint src[3], GrScalar t, GrPoint* pt) {
652 GrAssert(src);
653 GrAssert(pt);
654 GrAssert(t >= 0 && t <= GR_Scalar1);
655 pt->set(gr_eval_quad(&src[0].fX, t), gr_eval_quad(&src[0].fY, t));
656}
657
658static GrScalar gr_eval_cubic(const GrScalar coord[], GrScalar t) {
659 GrScalar A = coord[6] - coord[0] + 3 * (coord[2] - coord[4]);
660 GrScalar B = 3 * (coord[0] - 2 * coord[2] + coord[4]);
661 GrScalar C = 3 * (coord[2] - coord[0]);
662 GrScalar D = coord[0];
663
664 return GrMul(GrMul(GrMul(A, t) + B, t) + C, t) + D;
665}
666
667static void gr_eval_cubic_at(const GrPoint src[4], GrScalar t, GrPoint* pt) {
668 GrAssert(src);
669 GrAssert(pt);
670 GrAssert(t >= 0 && t <= GR_Scalar1);
671
672 pt->set(gr_eval_cubic(&src[0].fX, t), gr_eval_cubic(&src[0].fY, t));
673}
674
675#endif // !NEW_EVAL
676
677static int worst_case_point_count(GrPathIter* path,
678 int* subpaths,
679 const GrMatrix& matrix,
680 GrScalar tol) {
681 int pointCount = 0;
682 *subpaths = 1;
683
684 bool first = true;
685
686 GrPathIter::Command cmd;
687
688 GrPoint pts[4];
689 while ((cmd = path->next(pts)) != GrPathIter::kEnd_Command) {
690
691 switch (cmd) {
692 case GrPathIter::kLine_Command:
693 pointCount += 1;
694 break;
695 case GrPathIter::kQuadratic_Command:
696#if NEW_EVAL
697 matrix.mapPoints(pts, pts, 3);
698 pointCount += quadratic_point_count(pts, tol);
699#else
700 pointCount += 9;
701#endif
702 break;
703 case GrPathIter::kCubic_Command:
704#if NEW_EVAL
705 matrix.mapPoints(pts, pts, 4);
706 pointCount += cubic_point_count(pts, tol);
707#else
708 pointCount += 17;
709#endif
710 break;
711 case GrPathIter::kMove_Command:
712 pointCount += 1;
713 if (!first) {
714 ++(*subpaths);
715 }
716 break;
717 default:
718 break;
719 }
720 first = false;
721 }
722 return pointCount;
723}
724
725static inline bool single_pass_path(const GrPathIter& path,
726 GrContext::PathFills fill,
reed@google.comac10a2d2010-12-22 21:39:39 +0000727 const GrGpu& gpu) {
728#if STENCIL_OFF
729 return true;
730#else
731 if (GrContext::kEvenOdd_PathFill == fill) {
732 GrPathIter::ConvexHint hint = path.hint();
733 return hint == GrPathIter::kConvex_ConvexHint ||
734 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint;
735 } else if (GrContext::kWinding_PathFill == fill) {
736 GrPathIter::ConvexHint hint = path.hint();
737 return hint == GrPathIter::kConvex_ConvexHint ||
738 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint ||
739 (hint == GrPathIter::kSameWindingConvexPieces_ConvexHint &&
740 gpu.canDisableBlend() && !gpu.isDitherState());
741
742 }
743 return false;
744#endif
745}
746
bsalomon@google.com5782d712011-01-21 21:03:59 +0000747void GrContext::drawPath(const GrPaint& paint,
748 GrPathIter* path,
749 PathFills fill,
750 const GrPoint* translate) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000751
reed@google.comac10a2d2010-12-22 21:39:39 +0000752
bsalomon@google.com5782d712011-01-21 21:03:59 +0000753 this->prepareToDraw(paint);
754
755 GrDrawTarget::AutoStateRestore asr(fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000756
757#if NEW_EVAL
bsalomon@google.com5782d712011-01-21 21:03:59 +0000758 GrMatrix viewM = fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000759 // In order to tesselate the path we get a bound on how much the matrix can
760 // stretch when mapping to screen coordinates.
761 GrScalar stretch = viewM.getMaxStretch();
762 bool useStretch = stretch > 0;
763 GrScalar tol = EVAL_TOL;
764 if (!useStretch) {
765 // TODO: deal with perspective in some better way.
766 tol /= 10;
767 } else {
768 // TODO: fixed point divide
769 GrScalar sinv = 1 / stretch;
770 tol = GrMul(tol, sinv);
771 viewM = GrMatrix::I();
772 }
773 GrScalar tolSqd = GrMul(tol, tol);
774#else
775 // pass to worst_case... but won't be used.
776 static const GrScalar tol = -1;
777#endif
778
779 int subpathCnt;
780 int maxPts = worst_case_point_count(path,
781 &subpathCnt,
782#if CPU_TRANSFORM
783 cpuMatrix,
784#else
785 GrMatrix::I(),
786#endif
787 tol);
788 GrVertexLayout layout = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000789
790 if (NULL != paint.getTexture()) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000791 layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000792 }
793 // add 4 to hold the bounding rect
794 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, maxPts + 4, 0);
795
796 GrPoint* base = (GrPoint*) arg.vertices();
797 GrPoint* vert = base;
798 GrPoint* subpathBase = base;
799
800 GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
801
802 path->rewind();
803
804 // TODO: use primitve restart if available rather than multiple draws
bsalomon@google.com5782d712011-01-21 21:03:59 +0000805 GrDrawTarget::PrimitiveType type;
reed@google.comac10a2d2010-12-22 21:39:39 +0000806 int passCount = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000807 GrDrawTarget::StencilPass passes[3];
reed@google.comac10a2d2010-12-22 21:39:39 +0000808 bool reverse = false;
809
810 if (kHairLine_PathFill == fill) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000811 type = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000812 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000813 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000814 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000815 type = GrDrawTarget::kTriangleFan_PrimitiveType;
816 if (single_pass_path(*path, fill, *fGpu)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000817 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000818 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000819 } else {
820 switch (fill) {
821 case kInverseEvenOdd_PathFill:
822 reverse = true;
823 // fallthrough
824 case kEvenOdd_PathFill:
825 passCount = 2;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000826 passes[0] = GrDrawTarget::kEvenOddStencil_StencilPass;
827 passes[1] = GrDrawTarget::kEvenOddColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000828 break;
829
830 case kInverseWinding_PathFill:
831 reverse = true;
832 // fallthrough
833 case kWinding_PathFill:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000834 passes[0] = GrDrawTarget::kWindingStencil1_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000835 if (fGpu->supportsSingleStencilPassWinding()) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000836 passes[1] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000837 passCount = 2;
838 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000839 passes[1] = GrDrawTarget::kWindingStencil2_StencilPass;
840 passes[2] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000841 passCount = 3;
842 }
843 break;
844 default:
845 GrAssert(!"Unknown path fill!");
846 return;
847 }
848 }
849 }
850 fGpu->setReverseFill(reverse);
851#if CPU_TRANSFORM
852 GrMatrix cpuMatrix;
853 fGpu->getViewMatrix(&cpuMatrix);
854 fGpu->setViewMatrix(GrMatrix::I());
855#endif
856
857 GrPoint pts[4];
858
859 bool first = true;
860 int subpath = 0;
861
862 for (;;) {
863 GrPathIter::Command cmd = path->next(pts);
864#if CPU_TRANSFORM
865 int numPts = GrPathIter::NumCommandPoints(cmd);
866 cpuMatrix.mapPoints(pts, pts, numPts);
867#endif
868 switch (cmd) {
869 case GrPathIter::kMove_Command:
870 if (!first) {
871 subpathVertCount[subpath] = vert-subpathBase;
872 subpathBase = vert;
873 ++subpath;
874 }
875 *vert = pts[0];
876 vert++;
877 break;
878 case GrPathIter::kLine_Command:
879 *vert = pts[1];
880 vert++;
881 break;
882 case GrPathIter::kQuadratic_Command: {
883#if NEW_EVAL
884
885 generate_quadratic_points(pts[0], pts[1], pts[2],
886 tolSqd, &vert,
887 quadratic_point_count(pts, tol));
888#else
889 const int n = 8;
890 const GrScalar dt = GR_Scalar1 / n;
891 GrScalar t = dt;
892 for (int i = 1; i < n; i++) {
893 gr_eval_quad_at(pts, t, (GrPoint*)vert);
894 t += dt;
895 vert++;
896 }
897 vert->set(pts[2].fX, pts[2].fY);
898 vert++;
899#endif
900 break;
901 }
902 case GrPathIter::kCubic_Command: {
903#if NEW_EVAL
904 generate_cubic_points(pts[0], pts[1], pts[2], pts[3],
905 tolSqd, &vert,
906 cubic_point_count(pts, tol));
907#else
908 const int n = 16;
909 const GrScalar dt = GR_Scalar1 / n;
910 GrScalar t = dt;
911 for (int i = 1; i < n; i++) {
912 gr_eval_cubic_at(pts, t, (GrPoint*)vert);
913 t += dt;
914 vert++;
915 }
916 vert->set(pts[3].fX, pts[3].fY);
917 vert++;
918#endif
919 break;
920 }
921 case GrPathIter::kClose_Command:
922 break;
923 case GrPathIter::kEnd_Command:
924 subpathVertCount[subpath] = vert-subpathBase;
925 ++subpath; // this could be only in debug
926 goto FINISHED;
927 }
928 first = false;
929 }
930FINISHED:
931 GrAssert(subpath == subpathCnt);
932 GrAssert((vert - base) <= maxPts);
933
934 if (translate) {
935 int count = vert - base;
936 for (int i = 0; i < count; i++) {
937 base[i].offset(translate->fX, translate->fY);
938 }
939 }
940
941 // arbitrary path complexity cutoff
942 bool useBounds = fill != kHairLine_PathFill &&
943 (reverse || (vert - base) > 8);
944 GrPoint* boundsVerts = base + maxPts;
945 if (useBounds) {
946 GrRect bounds;
947 if (reverse) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000948 GrAssert(NULL != fGpu->getRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000949 // draw over the whole world.
950 bounds.setLTRB(0, 0,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000951 GrIntToScalar(fGpu->getRenderTarget()->width()),
952 GrIntToScalar(fGpu->getRenderTarget()->height()));
953 GrMatrix vmi;
954 if (fGpu->getViewInverse(&vmi)) {
955 vmi.mapRect(&bounds);
956 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000957 } else {
958 bounds.setBounds((GrPoint*)base, vert - base);
959 }
960 boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
961 bounds.fBottom);
962 }
963
964 for (int p = 0; p < passCount; ++p) {
965 fGpu->setStencilPass(passes[p]);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000966 if (useBounds && (GrDrawTarget::kEvenOddColor_StencilPass == passes[p] ||
967 GrDrawTarget::kWindingColor_StencilPass == passes[p])) {
968 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000969 maxPts, 4);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000970
reed@google.comac10a2d2010-12-22 21:39:39 +0000971 } else {
972 int baseVertex = 0;
973 for (int sp = 0; sp < subpathCnt; ++sp) {
974 fGpu->drawNonIndexed(type,
975 baseVertex,
976 subpathVertCount[sp]);
977 baseVertex += subpathVertCount[sp];
978 }
979 }
980 }
981}
982
bsalomon@google.com5782d712011-01-21 21:03:59 +0000983////////////////////////////////////////////////////////////////////////////////
984
reed@google.comac10a2d2010-12-22 21:39:39 +0000985void GrContext::flush(bool flushRenderTarget) {
986 flushText();
987 if (flushRenderTarget) {
988 fGpu->forceRenderTargetFlush();
989 }
990}
991
992void GrContext::flushText() {
993 fTextDrawBuffer.playback(fGpu);
994 fTextDrawBuffer.reset();
995}
996
997bool GrContext::readPixels(int left, int top, int width, int height,
998 GrTexture::PixelConfig config, void* buffer) {
999 this->flush(true);
1000 return fGpu->readPixels(left, top, width, height, config, buffer);
1001}
1002
1003void GrContext::writePixels(int left, int top, int width, int height,
1004 GrTexture::PixelConfig config, const void* buffer,
1005 size_t stride) {
bsalomon@google.com5782d712011-01-21 21:03:59 +00001006
1007 // TODO: when underlying api has a direct way to do this we should use it
1008 // (e.g. glDrawPixels on desktop GL).
1009
reed@google.comac10a2d2010-12-22 21:39:39 +00001010 const GrGpu::TextureDesc desc = {
1011 0, GrGpu::kNone_AALevel, width, height, config
1012 };
1013 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1014 if (NULL == texture) {
1015 return;
1016 }
1017
1018 this->flush(true);
1019
1020 GrAutoUnref aur(texture);
1021 GrDrawTarget::AutoStateRestore asr(fGpu);
1022
1023 GrMatrix matrix;
1024 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1025 fGpu->setViewMatrix(matrix);
1026 matrix.setScale(GR_Scalar1 / texture->allocWidth(),
1027 GR_Scalar1 / texture->allocHeight());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001028 fGpu->setTextureMatrix(0, matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +00001029
1030 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1031 fGpu->setAlpha(0xFF);
1032 fGpu->setBlendFunc(GrDrawTarget::kOne_BlendCoeff,
1033 GrDrawTarget::kZero_BlendCoeff);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +00001034 fGpu->setTexture(0, texture);
1035 fGpu->setSamplerState(0, GrSamplerState::ClampNoFilter());
reed@google.comac10a2d2010-12-22 21:39:39 +00001036
bsalomon@google.com5782d712011-01-21 21:03:59 +00001037 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1038 static const int VCOUNT = 4;
1039
1040 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1041 if (!geo.succeeded()) {
1042 return;
1043 }
1044 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1045 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, VCOUNT);
1046}
1047////////////////////////////////////////////////////////////////////////////////
1048
1049void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1050 target->setTexture(0, paint.getTexture());
1051 target->setTextureMatrix(0, paint.fTextureMatrix);
1052 target->setSamplerState(0, paint.fSampler);
1053 target->setColor(paint.fColor);
1054
1055 if (paint.fDither) {
1056 target->enableState(GrDrawTarget::kDither_StateBit);
1057 } else {
1058 target->disableState(GrDrawTarget::kDither_StateBit);
1059 }
1060 if (paint.fAntiAlias) {
1061 target->enableState(GrDrawTarget::kAntialias_StateBit);
1062 } else {
1063 target->disableState(GrDrawTarget::kAntialias_StateBit);
1064 }
1065 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1066}
1067
1068void GrContext::prepareToDraw(const GrPaint& paint) {
1069
1070 flushText();
1071 SetPaint(paint, fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +00001072}
1073
1074////////////////////////////////////////////////////////////////////////////////
1075
reed@google.comac10a2d2010-12-22 21:39:39 +00001076void GrContext::resetContext() {
1077 fGpu->resetContext();
1078}
1079
reed@google.comac10a2d2010-12-22 21:39:39 +00001080void GrContext::setRenderTarget(GrRenderTarget* target) {
1081 flushText();
1082 fGpu->setRenderTarget(target);
1083}
1084
bsalomon@google.com5782d712011-01-21 21:03:59 +00001085GrRenderTarget* GrContext::getRenderTarget() {
1086 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +00001087}
1088
bsalomon@google.com5782d712011-01-21 21:03:59 +00001089const GrRenderTarget* GrContext::getRenderTarget() const {
1090 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +00001091}
1092
bsalomon@google.com5782d712011-01-21 21:03:59 +00001093const GrMatrix& GrContext::getMatrix() const {
1094 return fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +00001095}
1096
bsalomon@google.com5782d712011-01-21 21:03:59 +00001097void GrContext::setMatrix(const GrMatrix& m) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001098 fGpu->setViewMatrix(m);
1099}
1100
bsalomon@google.com5782d712011-01-21 21:03:59 +00001101void GrContext::concatMatrix(const GrMatrix& m) const {
1102 fGpu->concatViewMatrix(m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001103}
1104
1105static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1106 intptr_t mask = 1 << shift;
1107 if (pred) {
1108 bits |= mask;
1109 } else {
1110 bits &= ~mask;
1111 }
1112 return bits;
1113}
1114
reed@google.comac10a2d2010-12-22 21:39:39 +00001115void GrContext::resetStats() {
1116 fGpu->resetStats();
1117}
1118
1119const GrGpu::Stats& GrContext::getStats() const {
1120 return fGpu->getStats();
1121}
1122
1123void GrContext::printStats() const {
1124 fGpu->printStats();
1125}
1126
1127GrContext::GrContext(GrGpu* gpu) :
1128 fVBAllocPool(gpu,
1129 gpu->supportsBufferLocking() ? POOL_VB_SIZE : 0,
1130 gpu->supportsBufferLocking() ? NUM_POOL_VBS : 0),
1131 fTextDrawBuffer(gpu->supportsBufferLocking() ? &fVBAllocPool : NULL) {
1132 fGpu = gpu;
1133 fGpu->ref();
1134 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1135 MAX_TEXTURE_CACHE_BYTES);
1136 fFontCache = new GrFontCache(fGpu);
1137}
1138
1139bool GrContext::finalizeTextureKey(GrTextureKey* key,
1140 const GrSamplerState& sampler) const {
1141 uint32_t bits = 0;
1142 uint16_t width = key->width();
1143 uint16_t height = key->height();
1144 if (fGpu->npotTextureSupport() < GrGpu::kNonRendertarget_NPOTTextureType) {
1145 if ((sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
1146 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode) &&
1147 (!GrIsPow2(width) || !GrIsPow2(height))) {
1148 bits |= 1;
1149 bits |= sampler.isFilter() ? 2 : 0;
1150 }
1151 }
1152 key->finalize(bits);
1153 return 0 != bits;
1154}
1155
bsalomon@google.com5782d712011-01-21 21:03:59 +00001156GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1157 GrDrawTarget* target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001158#if DEFER_TEXT_RENDERING
1159 fTextDrawBuffer.initializeDrawStateAndClip(*fGpu);
bsalomon@google.com5782d712011-01-21 21:03:59 +00001160 target = &fTextDrawBuffer;
reed@google.comac10a2d2010-12-22 21:39:39 +00001161#else
bsalomon@google.com5782d712011-01-21 21:03:59 +00001162 target = fGpu;
reed@google.comac10a2d2010-12-22 21:39:39 +00001163#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +00001164 SetPaint(paint, target);
1165 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001166}
1167
1168const GrIndexBuffer* GrContext::quadIndexBuffer() const {
1169 return fGpu->quadIndexBuffer();
1170}
1171
1172int GrContext::maxQuadsInIndexBuffer() const {
1173 return fGpu->maxQuadsInIndexBuffer();
1174}
1175
1176
1177