blob: 7ce8f35a650f7a2c21d3de0ae61d2e8b32df86a3 [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
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000245GrRenderTarget* GrContext::createPlatformRenderTarget(
246 intptr_t platformRenderTarget,
247 int stencilBits,
248 int width, int height) {
249 return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits,
reed@google.comac10a2d2010-12-22 21:39:39 +0000250 width, height);
251}
252
253bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
254 int width, int height) {
255 if (!fGpu->supports8BitPalette()) {
256 return false;
257 }
258
bsalomon@google.com0748f212011-02-01 22:56:16 +0000259
reed@google.comac10a2d2010-12-22 21:39:39 +0000260 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
261
bsalomon@google.com0748f212011-02-01 22:56:16 +0000262 if (!isPow2) {
263 if (!fGpu->npotTextureSupport()) {
264 return false;
265 }
266
267 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
268 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
269 if (tiled && !fGpu->npotTextureTileSupport()) {
270 return false;
271 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000272 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000273 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000274}
275
276////////////////////////////////////////////////////////////////////////////////
277
bsalomon@google.com5782d712011-01-21 21:03:59 +0000278void GrContext::setClip(const GrClip& clip) {
279 fGpu->setClip(clip);
280 fGpu->enableState(GrDrawTarget::kClip_StateBit);
281}
282
283void GrContext::setClip(const GrIRect& rect) {
284 GrClip clip;
285 clip.setRect(rect);
286 fGpu->setClip(clip);
287}
288
289////////////////////////////////////////////////////////////////////////////////
290
reed@google.comac10a2d2010-12-22 21:39:39 +0000291void GrContext::eraseColor(GrColor color) {
292 fGpu->eraseColor(color);
293}
294
bsalomon@google.com5782d712011-01-21 21:03:59 +0000295void GrContext::drawPaint(const GrPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000296 // set rect to be big enough to fill the space, but not super-huge, so we
297 // don't overflow fixed-point implementations
298 GrRect r(fGpu->getClip().getBounds());
299 GrMatrix inverse;
300 if (fGpu->getViewInverse(&inverse)) {
301 inverse.mapRect(&r);
302 } else {
303 GrPrintf("---- fGpu->getViewInverse failed\n");
304 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000305 this->drawRect(paint, r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000306}
307
308/* create a triangle strip that strokes the specified triangle. There are 8
309 unique vertices, but we repreat the last 2 to close up. Alternatively we
310 could use an indices array, and then only send 8 verts, but not sure that
311 would be faster.
312 */
313static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
314 GrScalar width) {
315 const GrScalar rad = GrScalarHalf(width);
316
317 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
318 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
319 verts[2].set(rect.fRight - rad, rect.fTop + rad);
320 verts[3].set(rect.fRight + rad, rect.fTop - rad);
321 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
322 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
323 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
324 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
325 verts[8] = verts[0];
326 verts[9] = verts[1];
327}
328
bsalomon@google.com5782d712011-01-21 21:03:59 +0000329void GrContext::drawRect(const GrPaint& paint,
330 const GrRect& rect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000331 GrScalar width,
332 const GrMatrix* matrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000333
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000334 bool textured = NULL != paint.getTexture();
reed@google.comac10a2d2010-12-22 21:39:39 +0000335
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000336 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +0000337
reed@google.comac10a2d2010-12-22 21:39:39 +0000338 if (width >= 0) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000339 // TODO: consider making static vertex buffers for these cases.
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000340 // Hairline could be done by just adding closing vertex to
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000341 // unitSquareVertexBuffer()
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000342 GrVertexLayout layout = (textured) ?
343 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
344 0;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000345 static const int worstCaseVertCount = 10;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000346 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000347
348 if (!geo.succeeded()) {
349 return;
350 }
351
352 GrDrawTarget::PrimitiveType primType;
353 int vertCount;
354 GrPoint* vertex = geo.positions();
355
reed@google.comac10a2d2010-12-22 21:39:39 +0000356 if (width > 0) {
357 vertCount = 10;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000358 primType = GrDrawTarget::kTriangleStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000359 setStrokeRectStrip(vertex, rect, width);
360 } else {
361 // hairline
362 vertCount = 5;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000363 primType = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000364 vertex[0].set(rect.fLeft, rect.fTop);
365 vertex[1].set(rect.fRight, rect.fTop);
366 vertex[2].set(rect.fRight, rect.fBottom);
367 vertex[3].set(rect.fLeft, rect.fBottom);
368 vertex[4].set(rect.fLeft, rect.fTop);
369 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000370
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000371 GrDrawTarget::AutoViewMatrixRestore avmr;
372 if (NULL != matrix) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000373 avmr.set(target);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000374 target->preConcatViewMatrix(*matrix);
375 target->preConcatSamplerMatrix(0, *matrix);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000376 }
377
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000378 target->drawNonIndexed(primType, 0, vertCount);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000379 } else {
bsalomon@google.com43333232011-02-02 19:24:54 +0000380 #if GR_STATIC_RECT_VB
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000381 GrVertexLayout layout = (textured) ?
382 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
383 0;
384 target->setVertexSourceToBuffer(layout,
385 fGpu->getUnitSquareVertexBuffer());
386 GrDrawTarget::AutoViewMatrixRestore avmr(target);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000387 GrMatrix m;
388 m.setAll(rect.width(), 0, rect.fLeft,
389 0, rect.height(), rect.fTop,
390 0, 0, GrMatrix::I()[8]);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000391
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000392 if (NULL != matrix) {
393 m.postConcat(*matrix);
394 }
395
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000396 target->preConcatViewMatrix(m);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000397
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000398 if (textured) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000399 target->preConcatSamplerMatrix(0, m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000400 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000401 target->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000402 #else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000403 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000404 #endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000405 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000406}
407
bsalomon@google.com5782d712011-01-21 21:03:59 +0000408void GrContext::drawRectToRect(const GrPaint& paint,
409 const GrRect& dstRect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000410 const GrRect& srcRect,
411 const GrMatrix* dstMatrix,
412 const GrMatrix* srcMatrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000413
414 if (NULL == paint.getTexture()) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000415 drawRect(paint, dstRect, -1, dstMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000416 return;
417 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000418
419 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000420
bsalomon@google.com43333232011-02-02 19:24:54 +0000421#if GR_STATIC_RECT_VB
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000422 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
423
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000424 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000425 GrDrawTarget::AutoViewMatrixRestore avmr(target);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000426
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000427 GrMatrix m;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000428
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000429 m.setAll(dstRect.width(), 0, dstRect.fLeft,
430 0, dstRect.height(), dstRect.fTop,
431 0, 0, GrMatrix::I()[8]);
432 if (NULL != dstMatrix) {
433 m.postConcat(*dstMatrix);
434 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000435 target->preConcatViewMatrix(m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000436
437 m.setAll(srcRect.width(), 0, srcRect.fLeft,
438 0, srcRect.height(), srcRect.fTop,
439 0, 0, GrMatrix::I()[8]);
440 if (NULL != srcMatrix) {
441 m.postConcat(*srcMatrix);
442 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000443 target->preConcatSamplerMatrix(0, m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000444
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000445 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
446 target->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000447#else
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000448
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000449 GrDrawTarget* target;
450#if BATCH_RECT_TO_RECT
451 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
452#else
453 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000454#endif
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000455
456 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
457 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
458 srcRects[0] = &srcRect;
459 srcMatrices[0] = srcMatrix;
460
461 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
462#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +0000463}
464
465void GrContext::drawVertices(const GrPaint& paint,
466 GrDrawTarget::PrimitiveType primitiveType,
467 int vertexCount,
468 const GrPoint positions[],
469 const GrPoint texCoords[],
470 const GrColor colors[],
471 const uint16_t indices[],
472 int indexCount) {
473 GrVertexLayout layout = 0;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000474 int vertexSize = sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000475
476 GrDrawTarget::AutoReleaseGeometry geo;
477
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000478 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000479
480 if (NULL != paint.getTexture()) {
481 if (NULL == texCoords) {
482 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
483 } else {
484 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000485 vertexSize += sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000486 }
487 }
488
489 if (NULL != colors) {
490 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000491 vertexSize += sizeof(GrColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000492 }
493
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000494 if (sizeof(GrPoint) != vertexSize) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000495 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000496 GrPrintf("Failed to get space for vertices!");
497 return;
498 }
499 int texOffsets[GrDrawTarget::kMaxTexCoords];
500 int colorOffset;
501 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
502 texOffsets,
503 &colorOffset);
504 void* curVertex = geo.vertices();
505
506 for (int i = 0; i < vertexCount; ++i) {
507 *((GrPoint*)curVertex) = positions[i];
508
509 if (texOffsets[0] > 0) {
510 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
511 }
512 if (colorOffset > 0) {
513 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
514 }
515 curVertex = (void*)((intptr_t)curVertex + vsize);
516 }
517 } else {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000518 target->setVertexSourceToArray(layout, positions, vertexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000519 }
520
521 if (NULL != indices) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000522 target->setIndexSourceToArray(indices, indexCount);
523 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000524 } else {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000525 target->drawNonIndexed(primitiveType, 0, vertexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000526 }
527}
528
529
reed@google.comac10a2d2010-12-22 21:39:39 +0000530////////////////////////////////////////////////////////////////////////////////
531
reed@google.comac10a2d2010-12-22 21:39:39 +0000532#define STENCIL_OFF 0 // Always disable stencil (even when needed)
reed@google.comac10a2d2010-12-22 21:39:39 +0000533#define EVAL_TOL GR_Scalar1
534
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000535static const uint32_t MAX_POINTS_PER_CURVE = 1 << 10;
536
reed@google.comac10a2d2010-12-22 21:39:39 +0000537static uint32_t quadratic_point_count(const GrPoint points[], GrScalar tol) {
538 GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);
539 // TODO: fixed points sqrt
540 if (d < tol) {
541 return 1;
542 } else {
543 // Each time we subdivide, d should be cut in 4. So we need to
544 // subdivide x = log4(d/tol) times. x subdivisions creates 2^(x)
545 // points.
546 // 2^(log4(x)) = sqrt(x);
547 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000548 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000549 }
550}
551
552static uint32_t generate_quadratic_points(const GrPoint& p0,
553 const GrPoint& p1,
554 const GrPoint& p2,
555 GrScalar tolSqd,
556 GrPoint** points,
557 uint32_t pointsLeft) {
558 if (pointsLeft < 2 ||
559 (p1.distanceToLineSegmentBetweenSqd(p0, p2)) < tolSqd) {
560 (*points)[0] = p2;
561 *points += 1;
562 return 1;
563 }
564
565 GrPoint q[] = {
566 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
567 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
568 };
569 GrPoint r(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY));
570
571 pointsLeft >>= 1;
572 uint32_t a = generate_quadratic_points(p0, q[0], r, tolSqd, points, pointsLeft);
573 uint32_t b = generate_quadratic_points(r, q[1], p2, tolSqd, points, pointsLeft);
574 return a + b;
575}
576
577static uint32_t cubic_point_count(const GrPoint points[], GrScalar tol) {
578 GrScalar d = GrMax(points[1].distanceToLineSegmentBetweenSqd(points[0], points[3]),
579 points[2].distanceToLineSegmentBetweenSqd(points[0], points[3]));
580 d = sqrtf(d);
581 if (d < tol) {
582 return 1;
583 } else {
584 d = ceilf(sqrtf(d/tol));
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000585 return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);
reed@google.comac10a2d2010-12-22 21:39:39 +0000586 }
587}
588
589static uint32_t generate_cubic_points(const GrPoint& p0,
590 const GrPoint& p1,
591 const GrPoint& p2,
592 const GrPoint& p3,
593 GrScalar tolSqd,
594 GrPoint** points,
595 uint32_t pointsLeft) {
596 if (pointsLeft < 2 ||
597 (p1.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd &&
598 p2.distanceToLineSegmentBetweenSqd(p0, p3) < tolSqd)) {
599 (*points)[0] = p3;
600 *points += 1;
601 return 1;
602 }
603 GrPoint q[] = {
604 GrPoint(GrScalarAve(p0.fX, p1.fX), GrScalarAve(p0.fY, p1.fY)),
605 GrPoint(GrScalarAve(p1.fX, p2.fX), GrScalarAve(p1.fY, p2.fY)),
606 GrPoint(GrScalarAve(p2.fX, p3.fX), GrScalarAve(p2.fY, p3.fY))
607 };
608 GrPoint r[] = {
609 GrPoint(GrScalarAve(q[0].fX, q[1].fX), GrScalarAve(q[0].fY, q[1].fY)),
610 GrPoint(GrScalarAve(q[1].fX, q[2].fX), GrScalarAve(q[1].fY, q[2].fY))
611 };
612 GrPoint s(GrScalarAve(r[0].fX, r[1].fX), GrScalarAve(r[0].fY, r[1].fY));
613 pointsLeft >>= 1;
614 uint32_t a = generate_cubic_points(p0, q[0], r[0], s, tolSqd, points, pointsLeft);
615 uint32_t b = generate_cubic_points(s, r[1], q[2], p3, tolSqd, points, pointsLeft);
616 return a + b;
617}
618
reed@google.comac10a2d2010-12-22 21:39:39 +0000619static int worst_case_point_count(GrPathIter* path,
620 int* subpaths,
reed@google.comac10a2d2010-12-22 21:39:39 +0000621 GrScalar tol) {
622 int pointCount = 0;
623 *subpaths = 1;
624
625 bool first = true;
626
627 GrPathIter::Command cmd;
628
629 GrPoint pts[4];
630 while ((cmd = path->next(pts)) != GrPathIter::kEnd_Command) {
631
632 switch (cmd) {
633 case GrPathIter::kLine_Command:
634 pointCount += 1;
635 break;
636 case GrPathIter::kQuadratic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000637 pointCount += quadratic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000638 break;
639 case GrPathIter::kCubic_Command:
reed@google.comac10a2d2010-12-22 21:39:39 +0000640 pointCount += cubic_point_count(pts, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000641 break;
642 case GrPathIter::kMove_Command:
643 pointCount += 1;
644 if (!first) {
645 ++(*subpaths);
646 }
647 break;
648 default:
649 break;
650 }
651 first = false;
652 }
653 return pointCount;
654}
655
656static inline bool single_pass_path(const GrPathIter& path,
657 GrContext::PathFills fill,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000658 const GrDrawTarget& target) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000659#if STENCIL_OFF
660 return true;
661#else
662 if (GrContext::kEvenOdd_PathFill == fill) {
663 GrPathIter::ConvexHint hint = path.hint();
664 return hint == GrPathIter::kConvex_ConvexHint ||
665 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint;
666 } else if (GrContext::kWinding_PathFill == fill) {
667 GrPathIter::ConvexHint hint = path.hint();
668 return hint == GrPathIter::kConvex_ConvexHint ||
669 hint == GrPathIter::kNonOverlappingConvexPieces_ConvexHint ||
670 (hint == GrPathIter::kSameWindingConvexPieces_ConvexHint &&
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000671 target.canDisableBlend() && !target.isDitherState());
reed@google.comac10a2d2010-12-22 21:39:39 +0000672
673 }
674 return false;
675#endif
676}
677
bsalomon@google.com5782d712011-01-21 21:03:59 +0000678void GrContext::drawPath(const GrPaint& paint,
679 GrPathIter* path,
680 PathFills fill,
681 const GrPoint* translate) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000682
reed@google.comac10a2d2010-12-22 21:39:39 +0000683
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000684 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000685
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000686 GrDrawTarget::AutoStateRestore asr(target);
reed@google.comac10a2d2010-12-22 21:39:39 +0000687
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000688 GrMatrix viewM = target->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000689 // In order to tesselate the path we get a bound on how much the matrix can
690 // stretch when mapping to screen coordinates.
691 GrScalar stretch = viewM.getMaxStretch();
692 bool useStretch = stretch > 0;
693 GrScalar tol = EVAL_TOL;
694 if (!useStretch) {
695 // TODO: deal with perspective in some better way.
696 tol /= 10;
697 } else {
698 // TODO: fixed point divide
699 GrScalar sinv = 1 / stretch;
700 tol = GrMul(tol, sinv);
reed@google.comac10a2d2010-12-22 21:39:39 +0000701 }
702 GrScalar tolSqd = GrMul(tol, tol);
reed@google.comac10a2d2010-12-22 21:39:39 +0000703
704 int subpathCnt;
705 int maxPts = worst_case_point_count(path,
706 &subpathCnt,
reed@google.comac10a2d2010-12-22 21:39:39 +0000707 tol);
708 GrVertexLayout layout = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000709
710 if (NULL != paint.getTexture()) {
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000711 layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000712 }
713 // add 4 to hold the bounding rect
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000714 GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);
reed@google.comac10a2d2010-12-22 21:39:39 +0000715
716 GrPoint* base = (GrPoint*) arg.vertices();
717 GrPoint* vert = base;
718 GrPoint* subpathBase = base;
719
720 GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
721
722 path->rewind();
723
724 // TODO: use primitve restart if available rather than multiple draws
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000725 GrDrawTarget::PrimitiveType type;
726 int passCount = 0;
727 GrDrawTarget::StencilPass passes[3];
728 bool reverse = false;
reed@google.comac10a2d2010-12-22 21:39:39 +0000729
730 if (kHairLine_PathFill == fill) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000731 type = GrDrawTarget::kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000732 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000733 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000734 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000735 type = GrDrawTarget::kTriangleFan_PrimitiveType;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000736 if (single_pass_path(*path, fill, *target)) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000737 passCount = 1;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000738 passes[0] = GrDrawTarget::kNone_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000739 } else {
740 switch (fill) {
741 case kInverseEvenOdd_PathFill:
742 reverse = true;
743 // fallthrough
744 case kEvenOdd_PathFill:
745 passCount = 2;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000746 passes[0] = GrDrawTarget::kEvenOddStencil_StencilPass;
747 passes[1] = GrDrawTarget::kEvenOddColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000748 break;
749
750 case kInverseWinding_PathFill:
751 reverse = true;
752 // fallthrough
753 case kWinding_PathFill:
bsalomon@google.com5782d712011-01-21 21:03:59 +0000754 passes[0] = GrDrawTarget::kWindingStencil1_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000755 if (fGpu->supportsSingleStencilPassWinding()) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000756 passes[1] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000757 passCount = 2;
758 } else {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000759 passes[1] = GrDrawTarget::kWindingStencil2_StencilPass;
760 passes[2] = GrDrawTarget::kWindingColor_StencilPass;
reed@google.comac10a2d2010-12-22 21:39:39 +0000761 passCount = 3;
762 }
763 break;
764 default:
765 GrAssert(!"Unknown path fill!");
766 return;
767 }
768 }
769 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000770 target->setReverseFill(reverse);
reed@google.comac10a2d2010-12-22 21:39:39 +0000771
772 GrPoint pts[4];
773
774 bool first = true;
775 int subpath = 0;
776
777 for (;;) {
778 GrPathIter::Command cmd = path->next(pts);
reed@google.comac10a2d2010-12-22 21:39:39 +0000779 switch (cmd) {
780 case GrPathIter::kMove_Command:
781 if (!first) {
782 subpathVertCount[subpath] = vert-subpathBase;
783 subpathBase = vert;
784 ++subpath;
785 }
786 *vert = pts[0];
787 vert++;
788 break;
789 case GrPathIter::kLine_Command:
790 *vert = pts[1];
791 vert++;
792 break;
793 case GrPathIter::kQuadratic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000794 generate_quadratic_points(pts[0], pts[1], pts[2],
795 tolSqd, &vert,
796 quadratic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000797 break;
798 }
799 case GrPathIter::kCubic_Command: {
reed@google.comac10a2d2010-12-22 21:39:39 +0000800 generate_cubic_points(pts[0], pts[1], pts[2], pts[3],
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000801 tolSqd, &vert,
reed@google.comac10a2d2010-12-22 21:39:39 +0000802 cubic_point_count(pts, tol));
reed@google.comac10a2d2010-12-22 21:39:39 +0000803 break;
804 }
805 case GrPathIter::kClose_Command:
806 break;
807 case GrPathIter::kEnd_Command:
808 subpathVertCount[subpath] = vert-subpathBase;
809 ++subpath; // this could be only in debug
810 goto FINISHED;
811 }
812 first = false;
813 }
814FINISHED:
815 GrAssert(subpath == subpathCnt);
816 GrAssert((vert - base) <= maxPts);
817
818 if (translate) {
819 int count = vert - base;
820 for (int i = 0; i < count; i++) {
821 base[i].offset(translate->fX, translate->fY);
822 }
823 }
824
825 // arbitrary path complexity cutoff
826 bool useBounds = fill != kHairLine_PathFill &&
827 (reverse || (vert - base) > 8);
828 GrPoint* boundsVerts = base + maxPts;
829 if (useBounds) {
830 GrRect bounds;
831 if (reverse) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000832 GrAssert(NULL != target->getRenderTarget());
reed@google.comac10a2d2010-12-22 21:39:39 +0000833 // draw over the whole world.
834 bounds.setLTRB(0, 0,
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000835 GrIntToScalar(target->getRenderTarget()->width()),
836 GrIntToScalar(target->getRenderTarget()->height()));
bsalomon@google.com5782d712011-01-21 21:03:59 +0000837 GrMatrix vmi;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000838 if (target->getViewInverse(&vmi)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000839 vmi.mapRect(&bounds);
840 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000841 } else {
842 bounds.setBounds((GrPoint*)base, vert - base);
843 }
844 boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
845 bounds.fBottom);
846 }
847
848 for (int p = 0; p < passCount; ++p) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000849 target->setStencilPass(passes[p]);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000850 if (useBounds && (GrDrawTarget::kEvenOddColor_StencilPass == passes[p] ||
851 GrDrawTarget::kWindingColor_StencilPass == passes[p])) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000852 target->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000853 maxPts, 4);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000854
reed@google.comac10a2d2010-12-22 21:39:39 +0000855 } else {
856 int baseVertex = 0;
857 for (int sp = 0; sp < subpathCnt; ++sp) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000858 target->drawNonIndexed(type,
reed@google.comac10a2d2010-12-22 21:39:39 +0000859 baseVertex,
860 subpathVertCount[sp]);
861 baseVertex += subpathVertCount[sp];
862 }
863 }
864 }
865}
866
bsalomon@google.com5782d712011-01-21 21:03:59 +0000867////////////////////////////////////////////////////////////////////////////////
868
reed@google.comac10a2d2010-12-22 21:39:39 +0000869void GrContext::flush(bool flushRenderTarget) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000870 flushDrawBuffer();
reed@google.comac10a2d2010-12-22 21:39:39 +0000871 if (flushRenderTarget) {
872 fGpu->forceRenderTargetFlush();
873 }
874}
875
876void GrContext::flushText() {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000877 if (kText_DrawCategory == fLastDrawCategory) {
878 flushDrawBuffer();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000879 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000880}
881
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000882void GrContext::flushDrawBuffer() {
883#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
884 fDrawBuffer->playback(fGpu);
885 fDrawBuffer->reset();
886#endif
887}
888
reed@google.comac10a2d2010-12-22 21:39:39 +0000889bool GrContext::readPixels(int left, int top, int width, int height,
890 GrTexture::PixelConfig config, void* buffer) {
891 this->flush(true);
892 return fGpu->readPixels(left, top, width, height, config, buffer);
893}
894
895void GrContext::writePixels(int left, int top, int width, int height,
896 GrTexture::PixelConfig config, const void* buffer,
897 size_t stride) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000898
899 // TODO: when underlying api has a direct way to do this we should use it
900 // (e.g. glDrawPixels on desktop GL).
901
reed@google.comac10a2d2010-12-22 21:39:39 +0000902 const GrGpu::TextureDesc desc = {
903 0, GrGpu::kNone_AALevel, width, height, config
904 };
905 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
906 if (NULL == texture) {
907 return;
908 }
909
910 this->flush(true);
911
912 GrAutoUnref aur(texture);
913 GrDrawTarget::AutoStateRestore asr(fGpu);
914
915 GrMatrix matrix;
916 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
917 fGpu->setViewMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000918
919 fGpu->disableState(GrDrawTarget::kClip_StateBit);
920 fGpu->setAlpha(0xFF);
921 fGpu->setBlendFunc(GrDrawTarget::kOne_BlendCoeff,
922 GrDrawTarget::kZero_BlendCoeff);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000923 fGpu->setTexture(0, texture);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000924
925 GrSamplerState sampler;
926 sampler.setClampNoFilter();
927 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
928 sampler.setMatrix(matrix);
929 fGpu->setSamplerState(0, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000930
bsalomon@google.com5782d712011-01-21 21:03:59 +0000931 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
932 static const int VCOUNT = 4;
933
934 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
935 if (!geo.succeeded()) {
936 return;
937 }
938 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
939 fGpu->drawNonIndexed(GrDrawTarget::kTriangleFan_PrimitiveType, 0, VCOUNT);
940}
941////////////////////////////////////////////////////////////////////////////////
942
943void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
944 target->setTexture(0, paint.getTexture());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000945 target->setSamplerState(0, paint.fSampler);
946 target->setColor(paint.fColor);
947
948 if (paint.fDither) {
949 target->enableState(GrDrawTarget::kDither_StateBit);
950 } else {
951 target->disableState(GrDrawTarget::kDither_StateBit);
952 }
953 if (paint.fAntiAlias) {
954 target->enableState(GrDrawTarget::kAntialias_StateBit);
955 } else {
956 target->disableState(GrDrawTarget::kAntialias_StateBit);
957 }
958 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
959}
960
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000961GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
962 DrawCategory category) {
963 if (category != fLastDrawCategory) {
964 flushDrawBuffer();
965 fLastDrawCategory = category;
966 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000967 SetPaint(paint, fGpu);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000968 GrDrawTarget* target = fGpu;
969 switch (category) {
970 case kText_DrawCategory:
971#if DEFER_TEXT_RENDERING
972 target = fDrawBuffer;
973 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
974#else
975 target = fGpu;
976#endif
977 break;
978 case kUnbuffered_DrawCategory:
979 target = fGpu;
980 break;
981 case kBuffered_DrawCategory:
982 target = fDrawBuffer;
983 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
984 break;
985 }
986 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +0000987}
988
989////////////////////////////////////////////////////////////////////////////////
990
reed@google.comac10a2d2010-12-22 21:39:39 +0000991void GrContext::resetContext() {
992 fGpu->resetContext();
993}
994
reed@google.comac10a2d2010-12-22 21:39:39 +0000995void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000996 flush(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000997 fGpu->setRenderTarget(target);
998}
999
bsalomon@google.com5782d712011-01-21 21:03:59 +00001000GrRenderTarget* GrContext::getRenderTarget() {
1001 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +00001002}
1003
bsalomon@google.com5782d712011-01-21 21:03:59 +00001004const GrRenderTarget* GrContext::getRenderTarget() const {
1005 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +00001006}
1007
bsalomon@google.com5782d712011-01-21 21:03:59 +00001008const GrMatrix& GrContext::getMatrix() const {
1009 return fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +00001010}
1011
bsalomon@google.com5782d712011-01-21 21:03:59 +00001012void GrContext::setMatrix(const GrMatrix& m) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001013 fGpu->setViewMatrix(m);
1014}
1015
bsalomon@google.com5782d712011-01-21 21:03:59 +00001016void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +00001017 fGpu->preConcatViewMatrix(m);
reed@google.comac10a2d2010-12-22 21:39:39 +00001018}
1019
1020static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1021 intptr_t mask = 1 << shift;
1022 if (pred) {
1023 bits |= mask;
1024 } else {
1025 bits &= ~mask;
1026 }
1027 return bits;
1028}
1029
reed@google.comac10a2d2010-12-22 21:39:39 +00001030void GrContext::resetStats() {
1031 fGpu->resetStats();
1032}
1033
1034const GrGpu::Stats& GrContext::getStats() const {
1035 return fGpu->getStats();
1036}
1037
1038void GrContext::printStats() const {
1039 fGpu->printStats();
1040}
1041
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001042GrContext::GrContext(GrGpu* gpu) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001043 fGpu = gpu;
1044 fGpu->ref();
1045 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1046 MAX_TEXTURE_CACHE_BYTES);
1047 fFontCache = new GrFontCache(fGpu);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001048
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001049 fLastDrawCategory = kUnbuffered_DrawCategory;
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001050
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001051#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
1052 fDrawBufferVBAllocPool =
1053 new GrVertexBufferAllocPool(gpu, false,
1054 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1055 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
1056 fDrawBufferIBAllocPool =
1057 new GrIndexBufferAllocPool(gpu, false,
1058 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1059 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1060
1061 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1062 fDrawBufferIBAllocPool);
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001063#else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001064 fDrawBuffer = NULL;
1065 fDrawBufferVBAllocPool = NULL;
1066 fDrawBufferIBAllocPool = NULL;
1067#endif
1068
1069#if BATCH_RECT_TO_RECT
1070 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com1c13c962011-02-14 16:51:21 +00001071#endif
1072
reed@google.comac10a2d2010-12-22 21:39:39 +00001073}
1074
1075bool GrContext::finalizeTextureKey(GrTextureKey* key,
1076 const GrSamplerState& sampler) const {
1077 uint32_t bits = 0;
1078 uint16_t width = key->width();
1079 uint16_t height = key->height();
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +00001080
bsalomon@google.com0748f212011-02-01 22:56:16 +00001081
1082 if (!fGpu->npotTextureTileSupport()) {
1083 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
1084
1085 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
1086 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
1087
1088 if (tiled && !isPow2) {
reed@google.comac10a2d2010-12-22 21:39:39 +00001089 bits |= 1;
1090 bits |= sampler.isFilter() ? 2 : 0;
1091 }
1092 }
1093 key->finalize(bits);
1094 return 0 != bits;
1095}
1096
bsalomon@google.com5782d712011-01-21 21:03:59 +00001097GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1098 GrDrawTarget* target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001099#if DEFER_TEXT_RENDERING
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001100 target = prepareToDraw(paint, kText_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +00001101#else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001102 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +00001103#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +00001104 SetPaint(paint, target);
1105 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +00001106}
1107
bsalomon@google.com86afc2a2011-02-16 16:12:19 +00001108const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1109 return fGpu->getQuadIndexBuffer();
reed@google.comac10a2d2010-12-22 21:39:39 +00001110}