blob: ad7f776a13c1f2f979e890c28b9bc848682e4a49 [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 }
132 GrTexture* clampTexture = clampEntry->texture();
133 GrGpu::TextureDesc rtDesc = desc;
134 rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag |
135 GrGpu::kNoPathRendering_TextureFlag;
136 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
137 fGpu->minRenderTargetWidth()));
138 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
139 fGpu->minRenderTargetHeight()));
140
141 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
142
143 if (NULL != texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000144 GrDrawTarget::AutoStateRestore asr(fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000145 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000146 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000147 fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000148 fGpu->setTextureMatrix(0, GrMatrix::I());
reed@google.comac10a2d2010-12-22 21:39:39 +0000149 fGpu->setViewMatrix(GrMatrix::I());
150 fGpu->setAlpha(0xff);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000151 fGpu->setBlendFunc(GrDrawTarget::kOne_BlendCoeff, GrDrawTarget::kZero_BlendCoeff);
152 fGpu->disableState(GrDrawTarget::kDither_StateBit |
153 GrDrawTarget::kClip_StateBit |
154 GrDrawTarget::kAntialias_StateBit);
reed@google.comac10a2d2010-12-22 21:39:39 +0000155 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
156 GrSamplerState::kClamp_WrapMode,
157 sampler.isFilter());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000158 fGpu->setSamplerState(0, stretchSampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000159
160 static const GrVertexLayout layout =
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000161 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000162 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
163
164 if (arg.succeeded()) {
165 GrPoint* verts = (GrPoint*) arg.vertices();
166 verts[0].setIRectFan(0, 0,
167 texture->contentWidth(),
168 texture->contentHeight(),
169 2*sizeof(GrPoint));
170 GrScalar tw = GrFixedToScalar(GR_Fixed1 *
171 clampTexture->contentWidth() /
172 clampTexture->allocWidth());
173 GrScalar th = GrFixedToScalar(GR_Fixed1 *
174 clampTexture->contentHeight() /
175 clampTexture->allocHeight());
176 verts[1].setRectFan(0, 0, tw, th, 2*sizeof(GrPoint));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000177 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000178 0, 4);
179 entry = fTextureCache->createAndLock(*key, texture);
180 }
181 texture->removeRenderTarget();
182 } else {
183 // TODO: Our CPU stretch doesn't filter. But we create separate
184 // stretched textures when the sampler state is either filtered or
185 // not. Either implement filtered stretch blit on CPU or just create
186 // one when FBO case fails.
187
188 rtDesc.fFlags = 0;
189 // no longer need to clamp at min RT size.
190 rtDesc.fWidth = GrNextPow2(desc.fWidth);
191 rtDesc.fHeight = GrNextPow2(desc.fHeight);
192 int bpp = GrTexture::BytesPerPixel(desc.fFormat);
193 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
194 rtDesc.fWidth *
195 rtDesc.fHeight);
196 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
197 srcData, desc.fWidth, desc.fHeight, bpp);
198
199 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
200
201 GrTexture* texture = fGpu->createTexture(rtDesc,
202 stretchedPixels.get(),
203 stretchedRowBytes);
204 GrAssert(NULL != texture);
205 entry = fTextureCache->createAndLock(*key, texture);
206 }
207 fTextureCache->unlock(clampEntry);
208
209 } else {
210 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
211 if (NULL != texture) {
212 entry = fTextureCache->createAndLock(*key, texture);
213 } else {
214 entry = NULL;
215 }
216 }
217 return entry;
218}
219
220void GrContext::unlockTexture(GrTextureEntry* entry) {
221 fTextureCache->unlock(entry);
222}
223
224void GrContext::detachCachedTexture(GrTextureEntry* entry) {
225 fTextureCache->detach(entry);
226}
227
228void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) {
229 fTextureCache->reattachAndUnlock(entry);
230}
231
232GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc,
233 void* srcData,
234 size_t rowBytes) {
235 return fGpu->createTexture(desc, srcData, rowBytes);
236}
237
reed@google.com01804b42011-01-18 21:50:41 +0000238void GrContext::getTextureCacheLimits(int* maxTextures,
239 size_t* maxTextureBytes) const {
240 fTextureCache->getLimits(maxTextures, maxTextureBytes);
241}
242
243void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
244 fTextureCache->setLimits(maxTextures, maxTextureBytes);
245}
246
reed@google.com02a7e6c2011-01-28 21:21:49 +0000247int GrContext::getMaxTextureDimension() {
248 return fGpu->maxTextureDimension();
249}
250
reed@google.com01804b42011-01-18 21:50:41 +0000251///////////////////////////////////////////////////////////////////////////////
252
reed@google.comac10a2d2010-12-22 21:39:39 +0000253GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,
254 int width, int height) {
255 return fGpu->createPlatformRenderTarget(platformRenderTarget,
256 width, height);
257}
258
259bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
260 int width, int height) {
261 if (!fGpu->supports8BitPalette()) {
262 return false;
263 }
264
bsalomon@google.com0748f212011-02-01 22:56:16 +0000265
reed@google.comac10a2d2010-12-22 21:39:39 +0000266 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
267
bsalomon@google.com0748f212011-02-01 22:56:16 +0000268 if (!isPow2) {
269 if (!fGpu->npotTextureSupport()) {
270 return false;
271 }
272
273 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
274 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
275 if (tiled && !fGpu->npotTextureTileSupport()) {
276 return false;
277 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000278 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000279 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000280}
281
282////////////////////////////////////////////////////////////////////////////////
283
bsalomon@google.com5782d712011-01-21 21:03:59 +0000284void GrContext::setClip(const GrClip& clip) {
285 fGpu->setClip(clip);
286 fGpu->enableState(GrDrawTarget::kClip_StateBit);
287}
288
289void GrContext::setClip(const GrIRect& rect) {
290 GrClip clip;
291 clip.setRect(rect);
292 fGpu->setClip(clip);
293}
294
295////////////////////////////////////////////////////////////////////////////////
296
reed@google.comac10a2d2010-12-22 21:39:39 +0000297void GrContext::eraseColor(GrColor color) {
298 fGpu->eraseColor(color);
299}
300
bsalomon@google.com5782d712011-01-21 21:03:59 +0000301void GrContext::drawPaint(const GrPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000302 // set rect to be big enough to fill the space, but not super-huge, so we
303 // don't overflow fixed-point implementations
304 GrRect r(fGpu->getClip().getBounds());
305 GrMatrix inverse;
306 if (fGpu->getViewInverse(&inverse)) {
307 inverse.mapRect(&r);
308 } else {
309 GrPrintf("---- fGpu->getViewInverse failed\n");
310 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000311 this->drawRect(paint, r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000312}
313
314/* create a triangle strip that strokes the specified triangle. There are 8
315 unique vertices, but we repreat the last 2 to close up. Alternatively we
316 could use an indices array, and then only send 8 verts, but not sure that
317 would be faster.
318 */
319static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
320 GrScalar width) {
321 const GrScalar rad = GrScalarHalf(width);
322
323 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
324 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
325 verts[2].set(rect.fRight - rad, rect.fTop + rad);
326 verts[3].set(rect.fRight + rad, rect.fTop - rad);
327 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
328 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
329 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
330 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
331 verts[8] = verts[0];
332 verts[9] = verts[1];
333}
334
bsalomon@google.com5782d712011-01-21 21:03:59 +0000335void GrContext::drawRect(const GrPaint& paint,
336 const GrRect& rect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000337 GrScalar width,
338 const GrMatrix* matrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000339
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000340 bool textured = NULL != paint.getTexture();
reed@google.comac10a2d2010-12-22 21:39:39 +0000341
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000342 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +0000343
reed@google.comac10a2d2010-12-22 21:39:39 +0000344 if (width >= 0) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000345 // TODO: consider making static vertex buffers for these cases.
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000346 // Hairline could be done by just adding closing vertex to
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000347 // unitSquareVertexBuffer()
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000348 GrVertexLayout layout = (textured) ?
349 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
350 0;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000351 static const int worstCaseVertCount = 10;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000352 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000353
354 if (!geo.succeeded()) {
355 return;
356 }
357
358 GrDrawTarget::PrimitiveType primType;
359 int vertCount;
360 GrPoint* vertex = geo.positions();
361
reed@google.comac10a2d2010-12-22 21:39:39 +0000362 if (width > 0) {
363 vertCount = 10;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000364 primType = GrDrawTarget::kTriangleStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000365 setStrokeRectStrip(vertex, rect, width);
366 } else {
367 // hairline
368 vertCount = 5;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000369 primType = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000370 vertex[0].set(rect.fLeft, rect.fTop);
371 vertex[1].set(rect.fRight, rect.fTop);
372 vertex[2].set(rect.fRight, rect.fBottom);
373 vertex[3].set(rect.fLeft, rect.fBottom);
374 vertex[4].set(rect.fLeft, rect.fTop);
375 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000376
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000377 GrDrawTarget::AutoViewMatrixRestore avmr;
378 if (NULL != matrix) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000379 avmr.set(target);
380 target->concatViewMatrix(*matrix);
381 target->concatTextureMatrix(0, *matrix);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000382 }
383
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000384 target->drawNonIndexed(primType, 0, vertCount);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000385 } else {
bsalomon@google.com43333232011-02-02 19:24:54 +0000386 #if GR_STATIC_RECT_VB
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000387 GrVertexLayout layout = (textured) ?
388 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
389 0;
390 target->setVertexSourceToBuffer(layout,
391 fGpu->getUnitSquareVertexBuffer());
392 GrDrawTarget::AutoViewMatrixRestore avmr(target);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000393 GrMatrix m;
394 m.setAll(rect.width(), 0, rect.fLeft,
395 0, rect.height(), rect.fTop,
396 0, 0, GrMatrix::I()[8]);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000397
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000398 if (NULL != matrix) {
399 m.postConcat(*matrix);
400 }
401
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000402 target->concatViewMatrix(m);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000403
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000404 if (textured) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000405 target->concatTextureMatrix(0, m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000406 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000407 target->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000408 #else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000409 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000410 #endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000411 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000412}
413
bsalomon@google.com5782d712011-01-21 21:03:59 +0000414void GrContext::drawRectToRect(const GrPaint& paint,
415 const GrRect& dstRect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000416 const GrRect& srcRect,
417 const GrMatrix* dstMatrix,
418 const GrMatrix* srcMatrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000419
420 if (NULL == paint.getTexture()) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000421 drawRect(paint, dstRect, -1, dstMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000422 return;
423 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000424
425 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000426
bsalomon@google.com43333232011-02-02 19:24:54 +0000427#if GR_STATIC_RECT_VB
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000428 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
429
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000430 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000431 GrDrawTarget::AutoViewMatrixRestore avmr(target);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000432
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000433 GrMatrix m;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000434
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000435 m.setAll(dstRect.width(), 0, dstRect.fLeft,
436 0, dstRect.height(), dstRect.fTop,
437 0, 0, GrMatrix::I()[8]);
438 if (NULL != dstMatrix) {
439 m.postConcat(*dstMatrix);
440 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000441 target->concatViewMatrix(m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000442
443 m.setAll(srcRect.width(), 0, srcRect.fLeft,
444 0, srcRect.height(), srcRect.fTop,
445 0, 0, GrMatrix::I()[8]);
446 if (NULL != srcMatrix) {
447 m.postConcat(*srcMatrix);
448 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000449 target->concatTextureMatrix(0, m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000450
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000451 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
452 target->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000453#else
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000454
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000455 GrDrawTarget* target;
456#if BATCH_RECT_TO_RECT
457 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
458#else
459 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000460#endif
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000461
462 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
463 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
464 srcRects[0] = &srcRect;
465 srcMatrices[0] = srcMatrix;
466
467 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
468#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +0000469}
470
471void GrContext::drawVertices(const GrPaint& paint,
472 GrDrawTarget::PrimitiveType primitiveType,
473 int vertexCount,
474 const GrPoint positions[],
475 const GrPoint texCoords[],
476 const GrColor colors[],
477 const uint16_t indices[],
478 int indexCount) {
479 GrVertexLayout layout = 0;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000480 int vertexSize = sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000481
482 GrDrawTarget::AutoReleaseGeometry geo;
483
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000484 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000485
486 if (NULL != paint.getTexture()) {
487 if (NULL == texCoords) {
488 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
489 } else {
490 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000491 vertexSize += sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000492 }
493 }
494
495 if (NULL != colors) {
496 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000497 vertexSize += sizeof(GrColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000498 }
499
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000500 if (sizeof(GrPoint) != vertexSize) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000501 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000502 GrPrintf("Failed to get space for vertices!");
503 return;
504 }
505 int texOffsets[GrDrawTarget::kMaxTexCoords];
506 int colorOffset;
507 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
508 texOffsets,
509 &colorOffset);
510 void* curVertex = geo.vertices();
511
512 for (int i = 0; i < vertexCount; ++i) {
513 *((GrPoint*)curVertex) = positions[i];
514
515 if (texOffsets[0] > 0) {
516 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
517 }
518 if (colorOffset > 0) {
519 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
520 }
521 curVertex = (void*)((intptr_t)curVertex + vsize);
522 }
523 } else {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000524 target->setVertexSourceToArray(layout, positions, vertexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000525 }
526
527 if (NULL != indices) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000528 target->setIndexSourceToArray(indices, indexCount);
529 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000530 } else {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000531 target->drawNonIndexed(primitiveType, 0, vertexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000532 }
533}
534
535
reed@google.comac10a2d2010-12-22 21:39:39 +0000536////////////////////////////////////////////////////////////////////////////////
537
reed@google.comac10a2d2010-12-22 21:39:39 +0000538#define STENCIL_OFF 0 // Always disable stencil (even when needed)
reed@google.comac10a2d2010-12-22 21:39:39 +0000539#define EVAL_TOL GR_Scalar1
540
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000541static const uint32_t MAX_POINTS_PER_CURVE = 1 << 10;
542
reed@google.comac10a2d2010-12-22 21:39:39 +0000543static uint32_t quadratic_point_count(const GrPoint points[], GrScalar tol) {
544 GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
545 // TODO: fixed points sqrt
546 if (d < tol) {
547 return 1;
548 } else {
549 // Each time we subdivide, d should be cut in 4. So we need to
550 // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
551 // points.
552 // 2^(log4(x)) = sqrt(x);
553 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000554 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000555 }
556}
557
558static uint32_t generate_quadratic_points(const GrPoint& p0,
559 const GrPoint& p1,
560 const GrPoint& p2,
561 GrScalar tolSqd,
562 GrPoint** points,
563 uint32_t pointsLeft) {
564 if (pointsLeft < 2 ||
565 (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
566 (*points)[0] = p2;
567 *points += 1;
568 return 1;
569 }
570
571 GrPoint q[] = {
572 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
573 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
574 };
575 GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY));
576
577 pointsLeft >>= 1;
578 uint32_t a = generate_quadratic_points(p0, q[0], r, tolSqd, points, pointsLeft);
579 uint32_t b = generate_quadratic_points(r, q[1], p2, tolSqd, points, pointsLeft);
580 return a + b;
581}
582
583static uint32_t cubic_point_count(const GrPoint points[], GrScalar tol) {
584 GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
585 points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
586 d = sqrtf(d);
587 if (d < tol) {
588 return 1;
589 } else {
590 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000591 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000592 }
593}
594
595static uint32_t generate_cubic_points(const GrPoint& p0,
596 const GrPoint& p1,
597 const GrPoint& p2,
598 const GrPoint& p3,
599 GrScalar tolSqd,
600 GrPoint** points,
601 uint32_t pointsLeft) {
602 if (pointsLeft < 2 ||
603 (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
604 p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
605 (*points)[0] = p3;
606 *points += 1;
607 return 1;
608 }
609 GrPoint q[] = {
610 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
611 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
612 GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY))
613 };
614 GrPoint r[] = {
615 GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)),
616 GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY))
617 };
618 GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY));
619 pointsLeft >>= 1;
620 uint32_t a = generate_cubic_points(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
621 uint32_t b = generate_cubic_points(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
622 return a + b;
623}
624
reed@google.comac10a2d2010-12-22 21:39:39 +0000625static int worst_case_point_count(GrPathIter* path,
626 int* subpaths,
reed@google.comac10a2d2010-12-22 21:39:39 +0000627 GrScalar tol) {
628 int pointCount = 0;
629 *subpaths = 1;
630
631 bool first = true;
632
633 GrPathIter::Command cmd;
634
635 GrPoint pts[4];
636 while ((cmd = path->next(pts)) != GrPathIter::kEnd_Command) {
637
638 switch (cmd) {
639 case GrPathIter::kLine_Command:
640 pointCount += 1;
641 break;
642 case GrPathIter::kQuadratic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000643 pointCount += quadratic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000644 break;
645 case GrPathIter::kCubic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000646 pointCount += cubic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000647 break;
648 case GrPathIter::kMove_Command:
649 pointCount += 1;
650 if (!first) {
651 ++(*subpaths);
652 }
653 break;
654 default:
655 break;
656 }
657 first = false;
658 }
659 return pointCount;
660}
661
662static inline bool single_pass_path(const GrPathIter& path,
663 GrContext::PathFills fill,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000664 const GrDrawTarget& target) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000665#if STENCIL_OFF
666 return true;
667#else
668 if (GrContext::kEvenOdd_PathFill == fill) {
669 GrPathIter::ConvexHint hint = path.hint();
670 return hint == GrPathIter::kConvex_ConvexHint ||
671 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint;
672 } else if (GrContext::kWinding_PathFill == fill) {
673 GrPathIter::ConvexHint hint = path.hint();
674 return hint == GrPathIter::kConvex_ConvexHint ||
675 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint ||
676 (hint == GrPathIter::kSameWindingConvexPieces_ConvexHint &&
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000677 target.canDisableBlend() && !target.isDitherState());
reed@google.comac10a2d2010-12-22 21:39:39 +0000678
679 }
680 return false;
681#endif
682}
683
bsalomon@google.com5782d712011-01-21 21:03:59 +0000684void GrContext::drawPath(const GrPaint& paint,
685 GrPathIter* path,
686 PathFills fill,
687 const GrPoint* translate) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000688
reed@google.comac10a2d2010-12-22 21:39:39 +0000689
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000690 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000691
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000692 GrDrawTarget::AutoStateRestore asr(target);
reed@google.comac10a2d2010-12-22 21:39:39 +0000693
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000694 GrMatrix viewM = target->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000695 // In order to tesselate the path we get a bound on how much the matrix can
696 // stretch when mapping to screen coordinates.
697 GrScalar stretch = viewM.getMaxStretch();
698 bool useStretch = stretch > 0;
699 GrScalar tol = EVAL_TOL;
700 if (!useStretch) {
701 // TODO: deal with perspective in some better way.
702 tol /= 10;
703 } else {
704 // TODO: fixed point divide
705 GrScalar sinv = 1 / stretch;
706 tol = GrMul(tol, sinv);
reed@google.comac10a2d2010-12-22 21:39:39 +0000707 }
708 GrScalar tolSqd = GrMul(tol, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000709
710 int subpathCnt;
711 int maxPts = worst_case_point_count(path,
712 &subpathCnt,
reed@google.comac10a2d2010-12-22 21:39:39 +0000713 tol);
714 GrVertexLayout layout = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000715
716 if (NULL != paint.getTexture()) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000717 layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000718 }
719 // add 4 to hold the bounding rect
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000720 GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000721
722 GrPoint* base = (GrPoint*) arg.vertices();
723 GrPoint* vert = base;
724 GrPoint* subpathBase = base;
725
726 GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
727
728 path->rewind();
729
730 // TODO: use primitve restart if available rather than multiple draws
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000731 GrDrawTarget::PrimitiveType type;
732 int passCount = 0;
733 GrDrawTarget::StencilPass passes[3];
734 bool reverse = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000735
736 if (kHairLine_PathFill == fill) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000737 type = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000738 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000739 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000740 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000741 type = GrDrawTarget::kTriangleFan_PrimitiveType;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000742 if (single_pass_path(*path, fill, *target)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000743 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000744 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000745 } else {
746 switch (fill) {
747 case kInverseEvenOdd_PathFill:
748 reverse = true;
749 // fallthrough
750 case kEvenOdd_PathFill:
751 passCount = 2;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000752 passes[0] = GrDrawTarget::kEvenOddStencil_StencilPass;
753 passes[1] = GrDrawTarget::kEvenOddColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000754 break;
755
756 case kInverseWinding_PathFill:
757 reverse = true;
758 // fallthrough
759 case kWinding_PathFill:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000760 passes[0] = GrDrawTarget::kWindingStencil1_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000761 if (fGpu->supportsSingleStencilPassWinding()) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000762 passes[1] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000763 passCount = 2;
764 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000765 passes[1] = GrDrawTarget::kWindingStencil2_StencilPass;
766 passes[2] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000767 passCount = 3;
768 }
769 break;
770 default:
771 GrAssert(!"Unknown path fill!");
772 return;
773 }
774 }
775 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000776 target->setReverseFill(reverse);
reed@google.comac10a2d2010-12-22 21:39:39 +0000777
778 GrPoint pts[4];
779
780 bool first = true;
781 int subpath = 0;
782
783 for (;;) {
784 GrPathIter::Command cmd = path->next(pts);
reed@google.comac10a2d2010-12-22 21:39:39 +0000785 switch (cmd) {
786 case GrPathIter::kMove_Command:
787 if (!first) {
788 subpathVertCount[subpath] = vert-subpathBase;
789 subpathBase = vert;
790 ++subpath;
791 }
792 *vert = pts[0];
793 vert++;
794 break;
795 case GrPathIter::kLine_Command:
796 *vert = pts[1];
797 vert++;
798 break;
799 case GrPathIter::kQuadratic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000800 generate_quadratic_points(pts[0], pts[1], pts[2],
801 tolSqd, &vert,
802 quadratic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000803 break;
804 }
805 case GrPathIter::kCubic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000806 generate_cubic_points(pts[0], pts[1], pts[2], pts[3],
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000807 tolSqd, &vert,
reed@google.comac10a2d2010-12-22 21:39:39 +0000808 cubic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000809 break;
810 }
811 case GrPathIter::kClose_Command:
812 break;
813 case GrPathIter::kEnd_Command:
814 subpathVertCount[subpath] = vert-subpathBase;
815 ++subpath; // this could be only in debug
816 goto FINISHED;
817 }
818 first = false;
819 }
820FINISHED:
821 GrAssert(subpath == subpathCnt);
822 GrAssert((vert - base) <= maxPts);
823
824 if (translate) {
825 int count = vert - base;
826 for (int i = 0; i < count; i++) {
827 base[i].offset(translate->fX, translate->fY);
828 }
829 }
830
831 // arbitrary path complexity cutoff
832 bool useBounds = fill != kHairLine_PathFill &&
833 (reverse || (vert - base) > 8);
834 GrPoint* boundsVerts = base + maxPts;
835 if (useBounds) {
836 GrRect bounds;
837 if (reverse) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000838 GrAssert(NULL != target->getRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000839 // draw over the whole world.
840 bounds.setLTRB(0, 0,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000841 GrIntToScalar(target->getRenderTarget()->width()),
842 GrIntToScalar(target->getRenderTarget()->height()));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000843 GrMatrix vmi;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000844 if (target->getViewInverse(&vmi)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000845 vmi.mapRect(&bounds);
846 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000847 } else {
848 bounds.setBounds((GrPoint*)base, vert - base);
849 }
850 boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
851 bounds.fBottom);
852 }
853
854 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000855 target->setStencilPass(passes[p]);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000856 if (useBounds && (GrDrawTarget::kEvenOddColor_StencilPass == passes[p] ||
857 GrDrawTarget::kWindingColor_StencilPass == passes[p])) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000858 target->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 maxPts, 4);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000860
reed@google.comac10a2d2010-12-22 21:39:39 +0000861 } else {
862 int baseVertex = 0;
863 for (int sp = 0; sp < subpathCnt; ++sp) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000864 target->drawNonIndexed(type,
reed@google.comac10a2d2010-12-22 21:39:39 +0000865 baseVertex,
866 subpathVertCount[sp]);
867 baseVertex += subpathVertCount[sp];
868 }
869 }
870 }
871}
872
bsalomon@google.com5782d712011-01-21 21:03:59 +0000873////////////////////////////////////////////////////////////////////////////////
874
reed@google.comac10a2d2010-12-22 21:39:39 +0000875void GrContext::flush(bool flushRenderTarget) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000876 flushDrawBuffer();
reed@google.comac10a2d2010-12-22 21:39:39 +0000877 if (flushRenderTarget) {
878 fGpu->forceRenderTargetFlush();
879 }
880}
881
882void GrContext::flushText() {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000883 if (kText_DrawCategory == fLastDrawCategory) {
884 flushDrawBuffer();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000885 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000886}
887
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000888void GrContext::flushDrawBuffer() {
889#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
890 fDrawBuffer->playback(fGpu);
891 fDrawBuffer->reset();
892#endif
893}
894
reed@google.comac10a2d2010-12-22 21:39:39 +0000895bool GrContext::readPixels(int left, int top, int width, int height,
896 GrTexture::PixelConfig config, void* buffer) {
897 this->flush(true);
898 return fGpu->readPixels(left, top, width, height, config, buffer);
899}
900
901void GrContext::writePixels(int left, int top, int width, int height,
902 GrTexture::PixelConfig config, const void* buffer,
903 size_t stride) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000904
905 // TODO: when underlying api has a direct way to do this we should use it
906 // (e.g. glDrawPixels on desktop GL).
907
reed@google.comac10a2d2010-12-22 21:39:39 +0000908 const GrGpu::TextureDesc desc = {
909 0, GrGpu::kNone_AALevel, width, height, config
910 };
911 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
912 if (NULL == texture) {
913 return;
914 }
915
916 this->flush(true);
917
918 GrAutoUnref aur(texture);
919 GrDrawTarget::AutoStateRestore asr(fGpu);
920
921 GrMatrix matrix;
922 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
923 fGpu->setViewMatrix(matrix);
924 matrix.setScale(GR_Scalar1 / texture->allocWidth(),
925 GR_Scalar1 / texture->allocHeight());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000926 fGpu->setTextureMatrix(0, matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000927
928 fGpu->disableState(GrDrawTarget::kClip_StateBit);
929 fGpu->setAlpha(0xFF);
930 fGpu->setBlendFunc(GrDrawTarget::kOne_BlendCoeff,
931 GrDrawTarget::kZero_BlendCoeff);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000932 fGpu->setTexture(0, texture);
933 fGpu->setSamplerState(0, GrSamplerState::ClampNoFilter());
reed@google.comac10a2d2010-12-22 21:39:39 +0000934
bsalomon@google.com5782d712011-01-21 21:03:59 +0000935 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
936 static const int VCOUNT = 4;
937
938 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
939 if (!geo.succeeded()) {
940 return;
941 }
942 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
943 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, VCOUNT);
944}
945////////////////////////////////////////////////////////////////////////////////
946
947void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
948 target->setTexture(0, paint.getTexture());
949 target->setTextureMatrix(0, paint.fTextureMatrix);
950 target->setSamplerState(0, paint.fSampler);
951 target->setColor(paint.fColor);
952
953 if (paint.fDither) {
954 target->enableState(GrDrawTarget::kDither_StateBit);
955 } else {
956 target->disableState(GrDrawTarget::kDither_StateBit);
957 }
958 if (paint.fAntiAlias) {
959 target->enableState(GrDrawTarget::kAntialias_StateBit);
960 } else {
961 target->disableState(GrDrawTarget::kAntialias_StateBit);
962 }
963 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
964}
965
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000966GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
967 DrawCategory category) {
968 if (category != fLastDrawCategory) {
969 flushDrawBuffer();
970 fLastDrawCategory = category;
971 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000972 SetPaint(paint, fGpu);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000973 GrDrawTarget* target = fGpu;
974 switch (category) {
975 case kText_DrawCategory:
976#if DEFER_TEXT_RENDERING
977 target = fDrawBuffer;
978 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
979#else
980 target = fGpu;
981#endif
982 break;
983 case kUnbuffered_DrawCategory:
984 target = fGpu;
985 break;
986 case kBuffered_DrawCategory:
987 target = fDrawBuffer;
988 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
989 break;
990 }
991 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +0000992}
993
994////////////////////////////////////////////////////////////////////////////////
995
reed@google.comac10a2d2010-12-22 21:39:39 +0000996void GrContext::resetContext() {
997 fGpu->resetContext();
998}
999
reed@google.comac10a2d2010-12-22 21:39:39 +00001000void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001001 flush(false);
reed@google.comac10a2d2010-12-22 21:39:39 +00001002 fGpu->setRenderTarget(target);
1003}
1004
bsalomon@google.com5782d712011-01-21 21:03:59 +00001005GrRenderTarget* GrContext::getRenderTarget() {
1006 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +00001007}
1008
bsalomon@google.com5782d712011-01-21 21:03:59 +00001009const GrRenderTarget* GrContext::getRenderTarget() const {
1010 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +00001011}
1012
bsalomon@google.com5782d712011-01-21 21:03:59 +00001013const GrMatrix& GrContext::getMatrix() const {
1014 return fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +00001015}
1016
bsalomon@google.com5782d712011-01-21 21:03:59 +00001017void GrContext::setMatrix(const GrMatrix& m) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001018 fGpu->setViewMatrix(m);
1019}
1020
bsalomon@google.com5782d712011-01-21 21:03:59 +00001021void GrContext::concatMatrix(const GrMatrix& m) const {
1022 fGpu->concatViewMatrix(m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001023}
1024
1025static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1026 intptr_t mask = 1 << shift;
1027 if (pred) {
1028 bits |= mask;
1029 } else {
1030 bits &= ~mask;
1031 }
1032 return bits;
1033}
1034
reed@google.comac10a2d2010-12-22 21:39:39 +00001035void GrContext::resetStats() {
1036 fGpu->resetStats();
1037}
1038
1039const GrGpu::Stats& GrContext::getStats() const {
1040 return fGpu->getStats();
1041}
1042
1043void GrContext::printStats() const {
1044 fGpu->printStats();
1045}
1046
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001047GrContext::GrContext(GrGpu* gpu) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001048 fGpu = gpu;
1049 fGpu->ref();
1050 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1051 MAX_TEXTURE_CACHE_BYTES);
1052 fFontCache = new GrFontCache(fGpu);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001053
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001054 fLastDrawCategory = kUnbuffered_DrawCategory;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001055
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001056#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
1057 fDrawBufferVBAllocPool =
1058 new GrVertexBufferAllocPool(gpu, false,
1059 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1060 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
1061 fDrawBufferIBAllocPool =
1062 new GrIndexBufferAllocPool(gpu, false,
1063 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1064 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1065
1066 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1067 fDrawBufferIBAllocPool);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001068#else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001069 fDrawBuffer = NULL;
1070 fDrawBufferVBAllocPool = NULL;
1071 fDrawBufferIBAllocPool = NULL;
1072#endif
1073
1074#if BATCH_RECT_TO_RECT
1075 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001076#endif
1077
reed@google.comac10a2d2010-12-22 21:39:39 +00001078}
1079
1080bool GrContext::finalizeTextureKey(GrTextureKey* key,
1081 const GrSamplerState& sampler) const {
1082 uint32_t bits = 0;
1083 uint16_t width = key->width();
1084 uint16_t height = key->height();
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001085
bsalomon@google.com0748f212011-02-01 22:56:16 +00001086
1087 if (!fGpu->npotTextureTileSupport()) {
1088 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
1089
1090 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
1091 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
1092
1093 if (tiled && !isPow2) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001094 bits |= 1;
1095 bits |= sampler.isFilter() ? 2 : 0;
1096 }
1097 }
1098 key->finalize(bits);
1099 return 0 != bits;
1100}
1101
bsalomon@google.com5782d712011-01-21 21:03:59 +00001102GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1103 GrDrawTarget* target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001104#if DEFER_TEXT_RENDERING
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001105 target = prepareToDraw(paint, kText_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +00001106#else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001107 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +00001108#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +00001109 SetPaint(paint, target);
1110 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001111}
1112
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001113const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1114 return fGpu->getQuadIndexBuffer();
reed@google.comac10a2d2010-12-22 21:39:39 +00001115}