blob: 0423483c300450e9d0e8bd12195284b5cde9250a [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
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000030#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
reed@google.comac10a2d2010-12-22 21:39:39 +000032static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
33static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
34
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000035static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
36static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
37
38// We are currently only batching Text and drawRectToRect, both
39// of which use the quad index buffer.
40static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
41static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +000042
43GrContext* GrContext::Create(GrGpu::Engine engine,
44 GrGpu::Platform3DContext context3D) {
45 GrContext* ctx = NULL;
46 GrGpu* fGpu = GrGpu::Create(engine, context3D);
47 if (NULL != fGpu) {
48 ctx = new GrContext(fGpu);
49 fGpu->unref();
50 }
51 return ctx;
52}
53
reed@google.com873cb1e2010-12-23 15:00:45 +000054GrContext* GrContext::CreateGLShaderContext() {
55 return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
56}
57
reed@google.comac10a2d2010-12-22 21:39:39 +000058GrContext::~GrContext() {
59 fGpu->unref();
60 delete fTextureCache;
61 delete fFontCache;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000062 delete fDrawBuffer;
63 delete fDrawBufferVBAllocPool;
64 delete fDrawBufferVBAllocPool;
reed@google.comac10a2d2010-12-22 21:39:39 +000065}
66
67void GrContext::abandonAllTextures() {
68 fTextureCache->deleteAll(GrTextureCache::kAbandonTexture_DeleteMode);
69 fFontCache->abandonAll();
70}
71
72GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
73 const GrSamplerState& sampler) {
74 finalizeTextureKey(key, sampler);
75 return fTextureCache->findAndLock(*key);
76}
77
78static void stretchImage(void* dst,
79 int dstW,
80 int dstH,
81 void* src,
82 int srcW,
83 int srcH,
84 int bpp) {
85 GrFixed dx = (srcW << 16) / dstW;
86 GrFixed dy = (srcH << 16) / dstH;
87
88 GrFixed y = dy >> 1;
89
90 int dstXLimit = dstW*bpp;
91 for (int j = 0; j < dstH; ++j) {
92 GrFixed x = dx >> 1;
93 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
94 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
95 for (int i = 0; i < dstXLimit; i += bpp) {
96 memcpy((uint8_t*) dstRow + i,
97 (uint8_t*) srcRow + (x>>16)*bpp,
98 bpp);
99 x += dx;
100 }
101 y += dy;
102 }
103}
104
105GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
106 const GrSamplerState& sampler,
107 const GrGpu::TextureDesc& desc,
108 void* srcData, size_t rowBytes) {
109 GrAssert(key->width() == desc.fWidth);
110 GrAssert(key->height() == desc.fHeight);
111
112#if GR_DUMP_TEXTURE_UPLOAD
113 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
114#endif
115
116 GrTextureEntry* entry = NULL;
117 bool special = finalizeTextureKey(key, sampler);
118 if (special) {
119 GrTextureEntry* clampEntry;
120 GrTextureKey clampKey(*key);
121 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
122
123 if (NULL == clampEntry) {
124 clampEntry = createAndLockTexture(&clampKey,
125 GrSamplerState::ClampNoFilter(),
126 desc, srcData, rowBytes);
127 GrAssert(NULL != clampEntry);
128 if (NULL == clampEntry) {
129 return NULL;
130 }
131 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000132 GrGpu::TextureDesc rtDesc = desc;
133 rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag |
134 GrGpu::kNoPathRendering_TextureFlag;
135 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
136 fGpu->minRenderTargetWidth()));
137 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
138 fGpu->minRenderTargetHeight()));
139
140 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
141
142 if (NULL != texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000143 GrDrawTarget::AutoStateRestore asr(fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000144 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000145 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000146 fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass);
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,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000165 texture->width(),
166 texture->height(),
reed@google.comac10a2d2010-12-22 21:39:39 +0000167 2*sizeof(GrPoint));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000168 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000169 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000170 0, 4);
171 entry = fTextureCache->createAndLock(*key, texture);
172 }
173 texture->removeRenderTarget();
174 } else {
175 // TODO: Our CPU stretch doesn't filter. But we create separate
176 // stretched textures when the sampler state is either filtered or
177 // not. Either implement filtered stretch blit on CPU or just create
178 // one when FBO case fails.
179
180 rtDesc.fFlags = 0;
181 // no longer need to clamp at min RT size.
182 rtDesc.fWidth = GrNextPow2(desc.fWidth);
183 rtDesc.fHeight = GrNextPow2(desc.fHeight);
184 int bpp = GrTexture::BytesPerPixel(desc.fFormat);
185 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
186 rtDesc.fWidth *
187 rtDesc.fHeight);
188 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
189 srcData, desc.fWidth, desc.fHeight, bpp);
190
191 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
192
193 GrTexture* texture = fGpu->createTexture(rtDesc,
194 stretchedPixels.get(),
195 stretchedRowBytes);
196 GrAssert(NULL != texture);
197 entry = fTextureCache->createAndLock(*key, texture);
198 }
199 fTextureCache->unlock(clampEntry);
200
201 } else {
202 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
203 if (NULL != texture) {
204 entry = fTextureCache->createAndLock(*key, texture);
205 } else {
206 entry = NULL;
207 }
208 }
209 return entry;
210}
211
212void GrContext::unlockTexture(GrTextureEntry* entry) {
213 fTextureCache->unlock(entry);
214}
215
216void GrContext::detachCachedTexture(GrTextureEntry* entry) {
217 fTextureCache->detach(entry);
218}
219
220void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) {
221 fTextureCache->reattachAndUnlock(entry);
222}
223
224GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc,
225 void* srcData,
226 size_t rowBytes) {
227 return fGpu->createTexture(desc, srcData, rowBytes);
228}
229
reed@google.com01804b42011-01-18 21:50:41 +0000230void GrContext::getTextureCacheLimits(int* maxTextures,
231 size_t* maxTextureBytes) const {
232 fTextureCache->getLimits(maxTextures, maxTextureBytes);
233}
234
235void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
236 fTextureCache->setLimits(maxTextures, maxTextureBytes);
237}
238
reed@google.com02a7e6c2011-01-28 21:21:49 +0000239int GrContext::getMaxTextureDimension() {
240 return fGpu->maxTextureDimension();
241}
242
reed@google.com01804b42011-01-18 21:50:41 +0000243///////////////////////////////////////////////////////////////////////////////
244
reed@google.comac10a2d2010-12-22 21:39:39 +0000245GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,
246 int width, int height) {
247 return fGpu->createPlatformRenderTarget(platformRenderTarget,
248 width, height);
249}
250
251bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
252 int width, int height) {
253 if (!fGpu->supports8BitPalette()) {
254 return false;
255 }
256
bsalomon@google.com0748f212011-02-01 22:56:16 +0000257
reed@google.comac10a2d2010-12-22 21:39:39 +0000258 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
259
bsalomon@google.com0748f212011-02-01 22:56:16 +0000260 if (!isPow2) {
261 if (!fGpu->npotTextureSupport()) {
262 return false;
263 }
264
265 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
266 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
267 if (tiled && !fGpu->npotTextureTileSupport()) {
268 return false;
269 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000270 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000271 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000272}
273
274////////////////////////////////////////////////////////////////////////////////
275
bsalomon@google.com5782d712011-01-21 21:03:59 +0000276void GrContext::setClip(const GrClip& clip) {
277 fGpu->setClip(clip);
278 fGpu->enableState(GrDrawTarget::kClip_StateBit);
279}
280
281void GrContext::setClip(const GrIRect& rect) {
282 GrClip clip;
283 clip.setRect(rect);
284 fGpu->setClip(clip);
285}
286
287////////////////////////////////////////////////////////////////////////////////
288
reed@google.comac10a2d2010-12-22 21:39:39 +0000289void GrContext::eraseColor(GrColor color) {
290 fGpu->eraseColor(color);
291}
292
bsalomon@google.com5782d712011-01-21 21:03:59 +0000293void GrContext::drawPaint(const GrPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000294 // set rect to be big enough to fill the space, but not super-huge, so we
295 // don't overflow fixed-point implementations
296 GrRect r(fGpu->getClip().getBounds());
297 GrMatrix inverse;
298 if (fGpu->getViewInverse(&inverse)) {
299 inverse.mapRect(&r);
300 } else {
301 GrPrintf("---- fGpu->getViewInverse failed\n");
302 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000303 this->drawRect(paint, r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000304}
305
306/* create a triangle strip that strokes the specified triangle. There are 8
307 unique vertices, but we repreat the last 2 to close up. Alternatively we
308 could use an indices array, and then only send 8 verts, but not sure that
309 would be faster.
310 */
311static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
312 GrScalar width) {
313 const GrScalar rad = GrScalarHalf(width);
314
315 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
316 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
317 verts[2].set(rect.fRight - rad, rect.fTop + rad);
318 verts[3].set(rect.fRight + rad, rect.fTop - rad);
319 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
320 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
321 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
322 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
323 verts[8] = verts[0];
324 verts[9] = verts[1];
325}
326
bsalomon@google.com5782d712011-01-21 21:03:59 +0000327void GrContext::drawRect(const GrPaint& paint,
328 const GrRect& rect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000329 GrScalar width,
330 const GrMatrix* matrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000331
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000332 bool textured = NULL != paint.getTexture();
reed@google.comac10a2d2010-12-22 21:39:39 +0000333
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000334 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +0000335
reed@google.comac10a2d2010-12-22 21:39:39 +0000336 if (width >= 0) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000337 // TODO: consider making static vertex buffers for these cases.
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000338 // Hairline could be done by just adding closing vertex to
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000339 // unitSquareVertexBuffer()
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000340 GrVertexLayout layout = (textured) ?
341 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
342 0;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000343 static const int worstCaseVertCount = 10;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000344 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000345
346 if (!geo.succeeded()) {
347 return;
348 }
349
350 GrDrawTarget::PrimitiveType primType;
351 int vertCount;
352 GrPoint* vertex = geo.positions();
353
reed@google.comac10a2d2010-12-22 21:39:39 +0000354 if (width > 0) {
355 vertCount = 10;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000356 primType = GrDrawTarget::kTriangleStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000357 setStrokeRectStrip(vertex, rect, width);
358 } else {
359 // hairline
360 vertCount = 5;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000361 primType = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000362 vertex[0].set(rect.fLeft, rect.fTop);
363 vertex[1].set(rect.fRight, rect.fTop);
364 vertex[2].set(rect.fRight, rect.fBottom);
365 vertex[3].set(rect.fLeft, rect.fBottom);
366 vertex[4].set(rect.fLeft, rect.fTop);
367 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000368
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000369 GrDrawTarget::AutoViewMatrixRestore avmr;
370 if (NULL != matrix) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000371 avmr.set(target);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000372 target->preConcatViewMatrix(*matrix);
373 target->preConcatSamplerMatrix(0, *matrix);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000374 }
375
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000376 target->drawNonIndexed(primType, 0, vertCount);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000377 } else {
bsalomon@google.com43333232011-02-02 19:24:54 +0000378 #if GR_STATIC_RECT_VB
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000379 GrVertexLayout layout = (textured) ?
380 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
381 0;
382 target->setVertexSourceToBuffer(layout,
383 fGpu->getUnitSquareVertexBuffer());
384 GrDrawTarget::AutoViewMatrixRestore avmr(target);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000385 GrMatrix m;
386 m.setAll(rect.width(), 0, rect.fLeft,
387 0, rect.height(), rect.fTop,
388 0, 0, GrMatrix::I()[8]);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000389
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000390 if (NULL != matrix) {
391 m.postConcat(*matrix);
392 }
393
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000394 target->preConcatViewMatrix(m);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000395
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000396 if (textured) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000397 target->preConcatSamplerMatrix(0, m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000398 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000399 target->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000400 #else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000401 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000402 #endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000403 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000404}
405
bsalomon@google.com5782d712011-01-21 21:03:59 +0000406void GrContext::drawRectToRect(const GrPaint& paint,
407 const GrRect& dstRect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000408 const GrRect& srcRect,
409 const GrMatrix* dstMatrix,
410 const GrMatrix* srcMatrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000411
412 if (NULL == paint.getTexture()) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000413 drawRect(paint, dstRect, -1, dstMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000414 return;
415 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000416
417 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000418
bsalomon@google.com43333232011-02-02 19:24:54 +0000419#if GR_STATIC_RECT_VB
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000420 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
421
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000422 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000423 GrDrawTarget::AutoViewMatrixRestore avmr(target);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000424
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000425 GrMatrix m;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000426
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000427 m.setAll(dstRect.width(), 0, dstRect.fLeft,
428 0, dstRect.height(), dstRect.fTop,
429 0, 0, GrMatrix::I()[8]);
430 if (NULL != dstMatrix) {
431 m.postConcat(*dstMatrix);
432 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000433 target->preConcatViewMatrix(m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000434
435 m.setAll(srcRect.width(), 0, srcRect.fLeft,
436 0, srcRect.height(), srcRect.fTop,
437 0, 0, GrMatrix::I()[8]);
438 if (NULL != srcMatrix) {
439 m.postConcat(*srcMatrix);
440 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000441 target->preConcatSamplerMatrix(0, m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000442
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000443 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
444 target->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000445#else
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000446
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000447 GrDrawTarget* target;
448#if BATCH_RECT_TO_RECT
449 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
450#else
451 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000452#endif
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000453
454 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
455 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
456 srcRects[0] = &srcRect;
457 srcMatrices[0] = srcMatrix;
458
459 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
460#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +0000461}
462
463void GrContext::drawVertices(const GrPaint& paint,
464 GrDrawTarget::PrimitiveType primitiveType,
465 int vertexCount,
466 const GrPoint positions[],
467 const GrPoint texCoords[],
468 const GrColor colors[],
469 const uint16_t indices[],
470 int indexCount) {
471 GrVertexLayout layout = 0;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000472 int vertexSize = sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000473
474 GrDrawTarget::AutoReleaseGeometry geo;
475
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000476 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000477
478 if (NULL != paint.getTexture()) {
479 if (NULL == texCoords) {
480 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
481 } else {
482 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000483 vertexSize += sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000484 }
485 }
486
487 if (NULL != colors) {
488 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000489 vertexSize += sizeof(GrColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000490 }
491
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000492 if (sizeof(GrPoint) != vertexSize) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000493 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000494 GrPrintf("Failed to get space for vertices!");
495 return;
496 }
497 int texOffsets[GrDrawTarget::kMaxTexCoords];
498 int colorOffset;
499 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
500 texOffsets,
501 &colorOffset);
502 void* curVertex = geo.vertices();
503
504 for (int i = 0; i < vertexCount; ++i) {
505 *((GrPoint*)curVertex) = positions[i];
506
507 if (texOffsets[0] > 0) {
508 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
509 }
510 if (colorOffset > 0) {
511 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
512 }
513 curVertex = (void*)((intptr_t)curVertex + vsize);
514 }
515 } else {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000516 target->setVertexSourceToArray(layout, positions, vertexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000517 }
518
519 if (NULL != indices) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000520 target->setIndexSourceToArray(indices, indexCount);
521 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000522 } else {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000523 target->drawNonIndexed(primitiveType, 0, vertexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000524 }
525}
526
527
reed@google.comac10a2d2010-12-22 21:39:39 +0000528////////////////////////////////////////////////////////////////////////////////
529
reed@google.comac10a2d2010-12-22 21:39:39 +0000530#define STENCIL_OFF 0 // Always disable stencil (even when needed)
reed@google.comac10a2d2010-12-22 21:39:39 +0000531#define EVAL_TOL GR_Scalar1
532
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000533static const uint32_t MAX_POINTS_PER_CURVE = 1 << 10;
534
reed@google.comac10a2d2010-12-22 21:39:39 +0000535static uint32_t quadratic_point_count(const GrPoint points[], GrScalar tol) {
536 GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
537 // TODO: fixed points sqrt
538 if (d < tol) {
539 return 1;
540 } else {
541 // Each time we subdivide, d should be cut in 4. So we need to
542 // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
543 // points.
544 // 2^(log4(x)) = sqrt(x);
545 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000546 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000547 }
548}
549
550static uint32_t generate_quadratic_points(const GrPoint& p0,
551 const GrPoint& p1,
552 const GrPoint& p2,
553 GrScalar tolSqd,
554 GrPoint** points,
555 uint32_t pointsLeft) {
556 if (pointsLeft < 2 ||
557 (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
558 (*points)[0] = p2;
559 *points += 1;
560 return 1;
561 }
562
563 GrPoint q[] = {
564 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
565 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
566 };
567 GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY));
568
569 pointsLeft >>= 1;
570 uint32_t a = generate_quadratic_points(p0, q[0], r, tolSqd, points, pointsLeft);
571 uint32_t b = generate_quadratic_points(r, q[1], p2, tolSqd, points, pointsLeft);
572 return a + b;
573}
574
575static uint32_t cubic_point_count(const GrPoint points[], GrScalar tol) {
576 GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
577 points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
578 d = sqrtf(d);
579 if (d < tol) {
580 return 1;
581 } else {
582 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000583 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000584 }
585}
586
587static uint32_t generate_cubic_points(const GrPoint& p0,
588 const GrPoint& p1,
589 const GrPoint& p2,
590 const GrPoint& p3,
591 GrScalar tolSqd,
592 GrPoint** points,
593 uint32_t pointsLeft) {
594 if (pointsLeft < 2 ||
595 (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
596 p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
597 (*points)[0] = p3;
598 *points += 1;
599 return 1;
600 }
601 GrPoint q[] = {
602 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
603 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
604 GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY))
605 };
606 GrPoint r[] = {
607 GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)),
608 GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY))
609 };
610 GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY));
611 pointsLeft >>= 1;
612 uint32_t a = generate_cubic_points(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
613 uint32_t b = generate_cubic_points(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
614 return a + b;
615}
616
reed@google.comac10a2d2010-12-22 21:39:39 +0000617static int worst_case_point_count(GrPathIter* path,
618 int* subpaths,
reed@google.comac10a2d2010-12-22 21:39:39 +0000619 GrScalar tol) {
620 int pointCount = 0;
621 *subpaths = 1;
622
623 bool first = true;
624
625 GrPathIter::Command cmd;
626
627 GrPoint pts[4];
628 while ((cmd = path->next(pts)) != GrPathIter::kEnd_Command) {
629
630 switch (cmd) {
631 case GrPathIter::kLine_Command:
632 pointCount += 1;
633 break;
634 case GrPathIter::kQuadratic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000635 pointCount += quadratic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000636 break;
637 case GrPathIter::kCubic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000638 pointCount += cubic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000639 break;
640 case GrPathIter::kMove_Command:
641 pointCount += 1;
642 if (!first) {
643 ++(*subpaths);
644 }
645 break;
646 default:
647 break;
648 }
649 first = false;
650 }
651 return pointCount;
652}
653
654static inline bool single_pass_path(const GrPathIter& path,
655 GrContext::PathFills fill,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000656 const GrDrawTarget& target) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000657#if STENCIL_OFF
658 return true;
659#else
660 if (GrContext::kEvenOdd_PathFill == fill) {
661 GrPathIter::ConvexHint hint = path.hint();
662 return hint == GrPathIter::kConvex_ConvexHint ||
663 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint;
664 } else if (GrContext::kWinding_PathFill == fill) {
665 GrPathIter::ConvexHint hint = path.hint();
666 return hint == GrPathIter::kConvex_ConvexHint ||
667 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint ||
668 (hint == GrPathIter::kSameWindingConvexPieces_ConvexHint &&
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000669 target.canDisableBlend() && !target.isDitherState());
reed@google.comac10a2d2010-12-22 21:39:39 +0000670
671 }
672 return false;
673#endif
674}
675
bsalomon@google.com5782d712011-01-21 21:03:59 +0000676void GrContext::drawPath(const GrPaint& paint,
677 GrPathIter* path,
678 PathFills fill,
679 const GrPoint* translate) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000680
reed@google.comac10a2d2010-12-22 21:39:39 +0000681
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000682 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000683
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000684 GrDrawTarget::AutoStateRestore asr(target);
reed@google.comac10a2d2010-12-22 21:39:39 +0000685
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000686 GrMatrix viewM = target->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000687 // In order to tesselate the path we get a bound on how much the matrix can
688 // stretch when mapping to screen coordinates.
689 GrScalar stretch = viewM.getMaxStretch();
690 bool useStretch = stretch > 0;
691 GrScalar tol = EVAL_TOL;
692 if (!useStretch) {
693 // TODO: deal with perspective in some better way.
694 tol /= 10;
695 } else {
696 // TODO: fixed point divide
697 GrScalar sinv = 1 / stretch;
698 tol = GrMul(tol, sinv);
reed@google.comac10a2d2010-12-22 21:39:39 +0000699 }
700 GrScalar tolSqd = GrMul(tol, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000701
702 int subpathCnt;
703 int maxPts = worst_case_point_count(path,
704 &subpathCnt,
reed@google.comac10a2d2010-12-22 21:39:39 +0000705 tol);
706 GrVertexLayout layout = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000707
708 if (NULL != paint.getTexture()) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000709 layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000710 }
711 // add 4 to hold the bounding rect
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000712 GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000713
714 GrPoint* base = (GrPoint*) arg.vertices();
715 GrPoint* vert = base;
716 GrPoint* subpathBase = base;
717
718 GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
719
720 path->rewind();
721
722 // TODO: use primitve restart if available rather than multiple draws
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000723 GrDrawTarget::PrimitiveType type;
724 int passCount = 0;
725 GrDrawTarget::StencilPass passes[3];
726 bool reverse = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000727
728 if (kHairLine_PathFill == fill) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000729 type = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000730 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000731 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000732 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000733 type = GrDrawTarget::kTriangleFan_PrimitiveType;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000734 if (single_pass_path(*path, fill, *target)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000735 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000736 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000737 } else {
738 switch (fill) {
739 case kInverseEvenOdd_PathFill:
740 reverse = true;
741 // fallthrough
742 case kEvenOdd_PathFill:
743 passCount = 2;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000744 passes[0] = GrDrawTarget::kEvenOddStencil_StencilPass;
745 passes[1] = GrDrawTarget::kEvenOddColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000746 break;
747
748 case kInverseWinding_PathFill:
749 reverse = true;
750 // fallthrough
751 case kWinding_PathFill:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000752 passes[0] = GrDrawTarget::kWindingStencil1_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000753 if (fGpu->supportsSingleStencilPassWinding()) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000754 passes[1] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000755 passCount = 2;
756 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000757 passes[1] = GrDrawTarget::kWindingStencil2_StencilPass;
758 passes[2] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000759 passCount = 3;
760 }
761 break;
762 default:
763 GrAssert(!"Unknown path fill!");
764 return;
765 }
766 }
767 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000768 target->setReverseFill(reverse);
reed@google.comac10a2d2010-12-22 21:39:39 +0000769
770 GrPoint pts[4];
771
772 bool first = true;
773 int subpath = 0;
774
775 for (;;) {
776 GrPathIter::Command cmd = path->next(pts);
reed@google.comac10a2d2010-12-22 21:39:39 +0000777 switch (cmd) {
778 case GrPathIter::kMove_Command:
779 if (!first) {
780 subpathVertCount[subpath] = vert-subpathBase;
781 subpathBase = vert;
782 ++subpath;
783 }
784 *vert = pts[0];
785 vert++;
786 break;
787 case GrPathIter::kLine_Command:
788 *vert = pts[1];
789 vert++;
790 break;
791 case GrPathIter::kQuadratic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000792 generate_quadratic_points(pts[0], pts[1], pts[2],
793 tolSqd, &vert,
794 quadratic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000795 break;
796 }
797 case GrPathIter::kCubic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000798 generate_cubic_points(pts[0], pts[1], pts[2], pts[3],
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000799 tolSqd, &vert,
reed@google.comac10a2d2010-12-22 21:39:39 +0000800 cubic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000801 break;
802 }
803 case GrPathIter::kClose_Command:
804 break;
805 case GrPathIter::kEnd_Command:
806 subpathVertCount[subpath] = vert-subpathBase;
807 ++subpath; // this could be only in debug
808 goto FINISHED;
809 }
810 first = false;
811 }
812FINISHED:
813 GrAssert(subpath == subpathCnt);
814 GrAssert((vert - base) <= maxPts);
815
816 if (translate) {
817 int count = vert - base;
818 for (int i = 0; i < count; i++) {
819 base[i].offset(translate->fX, translate->fY);
820 }
821 }
822
823 // arbitrary path complexity cutoff
824 bool useBounds = fill != kHairLine_PathFill &&
825 (reverse || (vert - base) > 8);
826 GrPoint* boundsVerts = base + maxPts;
827 if (useBounds) {
828 GrRect bounds;
829 if (reverse) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000830 GrAssert(NULL != target->getRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000831 // draw over the whole world.
832 bounds.setLTRB(0, 0,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000833 GrIntToScalar(target->getRenderTarget()->width()),
834 GrIntToScalar(target->getRenderTarget()->height()));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000835 GrMatrix vmi;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000836 if (target->getViewInverse(&vmi)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000837 vmi.mapRect(&bounds);
838 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000839 } else {
840 bounds.setBounds((GrPoint*)base, vert - base);
841 }
842 boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
843 bounds.fBottom);
844 }
845
846 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000847 target->setStencilPass(passes[p]);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000848 if (useBounds && (GrDrawTarget::kEvenOddColor_StencilPass == passes[p] ||
849 GrDrawTarget::kWindingColor_StencilPass == passes[p])) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000850 target->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000851 maxPts, 4);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000852
reed@google.comac10a2d2010-12-22 21:39:39 +0000853 } else {
854 int baseVertex = 0;
855 for (int sp = 0; sp < subpathCnt; ++sp) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000856 target->drawNonIndexed(type,
reed@google.comac10a2d2010-12-22 21:39:39 +0000857 baseVertex,
858 subpathVertCount[sp]);
859 baseVertex += subpathVertCount[sp];
860 }
861 }
862 }
863}
864
bsalomon@google.com5782d712011-01-21 21:03:59 +0000865////////////////////////////////////////////////////////////////////////////////
866
reed@google.comac10a2d2010-12-22 21:39:39 +0000867void GrContext::flush(bool flushRenderTarget) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000868 flushDrawBuffer();
reed@google.comac10a2d2010-12-22 21:39:39 +0000869 if (flushRenderTarget) {
870 fGpu->forceRenderTargetFlush();
871 }
872}
873
874void GrContext::flushText() {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000875 if (kText_DrawCategory == fLastDrawCategory) {
876 flushDrawBuffer();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000877 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000878}
879
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000880void GrContext::flushDrawBuffer() {
881#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
882 fDrawBuffer->playback(fGpu);
883 fDrawBuffer->reset();
884#endif
885}
886
reed@google.comac10a2d2010-12-22 21:39:39 +0000887bool GrContext::readPixels(int left, int top, int width, int height,
888 GrTexture::PixelConfig config, void* buffer) {
889 this->flush(true);
890 return fGpu->readPixels(left, top, width, height, config, buffer);
891}
892
893void GrContext::writePixels(int left, int top, int width, int height,
894 GrTexture::PixelConfig config, const void* buffer,
895 size_t stride) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000896
897 // TODO: when underlying api has a direct way to do this we should use it
898 // (e.g. glDrawPixels on desktop GL).
899
reed@google.comac10a2d2010-12-22 21:39:39 +0000900 const GrGpu::TextureDesc desc = {
901 0, GrGpu::kNone_AALevel, width, height, config
902 };
903 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
904 if (NULL == texture) {
905 return;
906 }
907
908 this->flush(true);
909
910 GrAutoUnref aur(texture);
911 GrDrawTarget::AutoStateRestore asr(fGpu);
912
913 GrMatrix matrix;
914 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
915 fGpu->setViewMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000916
917 fGpu->disableState(GrDrawTarget::kClip_StateBit);
918 fGpu->setAlpha(0xFF);
919 fGpu->setBlendFunc(GrDrawTarget::kOne_BlendCoeff,
920 GrDrawTarget::kZero_BlendCoeff);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000921 fGpu->setTexture(0, texture);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000922
923 GrSamplerState sampler;
924 sampler.setClampNoFilter();
925 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
926 sampler.setMatrix(matrix);
927 fGpu->setSamplerState(0, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000928
bsalomon@google.com5782d712011-01-21 21:03:59 +0000929 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
930 static const int VCOUNT = 4;
931
932 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
933 if (!geo.succeeded()) {
934 return;
935 }
936 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
937 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, VCOUNT);
938}
939////////////////////////////////////////////////////////////////////////////////
940
941void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
942 target->setTexture(0, paint.getTexture());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000943 target->setSamplerState(0, paint.fSampler);
944 target->setColor(paint.fColor);
945
946 if (paint.fDither) {
947 target->enableState(GrDrawTarget::kDither_StateBit);
948 } else {
949 target->disableState(GrDrawTarget::kDither_StateBit);
950 }
951 if (paint.fAntiAlias) {
952 target->enableState(GrDrawTarget::kAntialias_StateBit);
953 } else {
954 target->disableState(GrDrawTarget::kAntialias_StateBit);
955 }
956 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
957}
958
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000959GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
960 DrawCategory category) {
961 if (category != fLastDrawCategory) {
962 flushDrawBuffer();
963 fLastDrawCategory = category;
964 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000965 SetPaint(paint, fGpu);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000966 GrDrawTarget* target = fGpu;
967 switch (category) {
968 case kText_DrawCategory:
969#if DEFER_TEXT_RENDERING
970 target = fDrawBuffer;
971 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
972#else
973 target = fGpu;
974#endif
975 break;
976 case kUnbuffered_DrawCategory:
977 target = fGpu;
978 break;
979 case kBuffered_DrawCategory:
980 target = fDrawBuffer;
981 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
982 break;
983 }
984 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +0000985}
986
987////////////////////////////////////////////////////////////////////////////////
988
reed@google.comac10a2d2010-12-22 21:39:39 +0000989void GrContext::resetContext() {
990 fGpu->resetContext();
991}
992
reed@google.comac10a2d2010-12-22 21:39:39 +0000993void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000994 flush(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000995 fGpu->setRenderTarget(target);
996}
997
bsalomon@google.com5782d712011-01-21 21:03:59 +0000998GrRenderTarget* GrContext::getRenderTarget() {
999 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +00001000}
1001
bsalomon@google.com5782d712011-01-21 21:03:59 +00001002const GrRenderTarget* GrContext::getRenderTarget() const {
1003 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +00001004}
1005
bsalomon@google.com5782d712011-01-21 21:03:59 +00001006const GrMatrix& GrContext::getMatrix() const {
1007 return fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +00001008}
1009
bsalomon@google.com5782d712011-01-21 21:03:59 +00001010void GrContext::setMatrix(const GrMatrix& m) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001011 fGpu->setViewMatrix(m);
1012}
1013
bsalomon@google.com5782d712011-01-21 21:03:59 +00001014void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001015 fGpu->preConcatViewMatrix(m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001016}
1017
1018static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1019 intptr_t mask = 1 << shift;
1020 if (pred) {
1021 bits |= mask;
1022 } else {
1023 bits &= ~mask;
1024 }
1025 return bits;
1026}
1027
reed@google.comac10a2d2010-12-22 21:39:39 +00001028void GrContext::resetStats() {
1029 fGpu->resetStats();
1030}
1031
1032const GrGpu::Stats& GrContext::getStats() const {
1033 return fGpu->getStats();
1034}
1035
1036void GrContext::printStats() const {
1037 fGpu->printStats();
1038}
1039
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001040GrContext::GrContext(GrGpu* gpu) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001041 fGpu = gpu;
1042 fGpu->ref();
1043 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1044 MAX_TEXTURE_CACHE_BYTES);
1045 fFontCache = new GrFontCache(fGpu);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001046
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001047 fLastDrawCategory = kUnbuffered_DrawCategory;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001048
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001049#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
1050 fDrawBufferVBAllocPool =
1051 new GrVertexBufferAllocPool(gpu, false,
1052 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1053 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
1054 fDrawBufferIBAllocPool =
1055 new GrIndexBufferAllocPool(gpu, false,
1056 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1057 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1058
1059 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1060 fDrawBufferIBAllocPool);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001061#else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001062 fDrawBuffer = NULL;
1063 fDrawBufferVBAllocPool = NULL;
1064 fDrawBufferIBAllocPool = NULL;
1065#endif
1066
1067#if BATCH_RECT_TO_RECT
1068 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001069#endif
1070
reed@google.comac10a2d2010-12-22 21:39:39 +00001071}
1072
1073bool GrContext::finalizeTextureKey(GrTextureKey* key,
1074 const GrSamplerState& sampler) const {
1075 uint32_t bits = 0;
1076 uint16_t width = key->width();
1077 uint16_t height = key->height();
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001078
bsalomon@google.com0748f212011-02-01 22:56:16 +00001079
1080 if (!fGpu->npotTextureTileSupport()) {
1081 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
1082
1083 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
1084 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
1085
1086 if (tiled && !isPow2) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001087 bits |= 1;
1088 bits |= sampler.isFilter() ? 2 : 0;
1089 }
1090 }
1091 key->finalize(bits);
1092 return 0 != bits;
1093}
1094
bsalomon@google.com5782d712011-01-21 21:03:59 +00001095GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1096 GrDrawTarget* target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001097#if DEFER_TEXT_RENDERING
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001098 target = prepareToDraw(paint, kText_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +00001099#else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001100 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +00001101#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +00001102 SetPaint(paint, target);
1103 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001104}
1105
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001106const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1107 return fGpu->getQuadIndexBuffer();
reed@google.comac10a2d2010-12-22 21:39:39 +00001108}