blob: dbc7f6ce18b3010f93472c62c62d5aa50a908a37 [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"
bsalomon@google.comffca4002011-02-22 20:34:01 +000027#include "GrPathRenderer.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000028
29#define DEFER_TEXT_RENDERING 1
30
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000031#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
32
reed@google.comac10a2d2010-12-22 21:39:39 +000033static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
34static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
35
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000036static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
37static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
38
39// We are currently only batching Text and drawRectToRect, both
40// of which use the quad index buffer.
41static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
42static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
reed@google.comac10a2d2010-12-22 21:39:39 +000043
44GrContext* GrContext::Create(GrGpu::Engine engine,
45 GrGpu::Platform3DContext context3D) {
46 GrContext* ctx = NULL;
47 GrGpu* fGpu = GrGpu::Create(engine, context3D);
48 if (NULL != fGpu) {
49 ctx = new GrContext(fGpu);
50 fGpu->unref();
51 }
52 return ctx;
53}
54
reed@google.com873cb1e2010-12-23 15:00:45 +000055GrContext* GrContext::CreateGLShaderContext() {
56 return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
57}
58
reed@google.comac10a2d2010-12-22 21:39:39 +000059GrContext::~GrContext() {
60 fGpu->unref();
61 delete fTextureCache;
62 delete fFontCache;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +000063 delete fDrawBuffer;
64 delete fDrawBufferVBAllocPool;
65 delete fDrawBufferVBAllocPool;
bsalomon@google.comffca4002011-02-22 20:34:01 +000066 delete fPathRenderer;
reed@google.comac10a2d2010-12-22 21:39:39 +000067}
68
69void GrContext::abandonAllTextures() {
70 fTextureCache->deleteAll(GrTextureCache::kAbandonTexture_DeleteMode);
71 fFontCache->abandonAll();
72}
73
74GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
75 const GrSamplerState& sampler) {
76 finalizeTextureKey(key, sampler);
77 return fTextureCache->findAndLock(*key);
78}
79
80static void stretchImage(void* dst,
81 int dstW,
82 int dstH,
83 void* src,
84 int srcW,
85 int srcH,
86 int bpp) {
87 GrFixed dx = (srcW << 16) / dstW;
88 GrFixed dy = (srcH << 16) / dstH;
89
90 GrFixed y = dy >> 1;
91
92 int dstXLimit = dstW*bpp;
93 for (int j = 0; j < dstH; ++j) {
94 GrFixed x = dx >> 1;
95 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
96 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
97 for (int i = 0; i < dstXLimit; i += bpp) {
98 memcpy((uint8_t*) dstRow + i,
99 (uint8_t*) srcRow + (x>>16)*bpp,
100 bpp);
101 x += dx;
102 }
103 y += dy;
104 }
105}
106
107GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
108 const GrSamplerState& sampler,
109 const GrGpu::TextureDesc& desc,
110 void* srcData, size_t rowBytes) {
111 GrAssert(key->width() == desc.fWidth);
112 GrAssert(key->height() == desc.fHeight);
113
114#if GR_DUMP_TEXTURE_UPLOAD
115 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
116#endif
117
118 GrTextureEntry* entry = NULL;
119 bool special = finalizeTextureKey(key, sampler);
120 if (special) {
121 GrTextureEntry* clampEntry;
122 GrTextureKey clampKey(*key);
123 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
124
125 if (NULL == clampEntry) {
126 clampEntry = createAndLockTexture(&clampKey,
127 GrSamplerState::ClampNoFilter(),
128 desc, srcData, rowBytes);
129 GrAssert(NULL != clampEntry);
130 if (NULL == clampEntry) {
131 return NULL;
132 }
133 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000134 GrGpu::TextureDesc rtDesc = desc;
135 rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag |
136 GrGpu::kNoPathRendering_TextureFlag;
137 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
138 fGpu->minRenderTargetWidth()));
139 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
140 fGpu->minRenderTargetHeight()));
141
142 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
143
144 if (NULL != texture) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000145 GrDrawTarget::AutoStateRestore asr(fGpu);
reed@google.comac10a2d2010-12-22 21:39:39 +0000146 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000147 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000148 fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass);
reed@google.comac10a2d2010-12-22 21:39:39 +0000149 fGpu->setViewMatrix(GrMatrix::I());
150 fGpu->setAlpha(0xff);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000151 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000152 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,
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000167 texture->width(),
168 texture->height(),
reed@google.comac10a2d2010-12-22 21:39:39 +0000169 2*sizeof(GrPoint));
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000170 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
bsalomon@google.comffca4002011-02-22 20:34:01 +0000171 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
reed@google.comac10a2d2010-12-22 21:39:39 +0000172 0, 4);
173 entry = fTextureCache->createAndLock(*key, texture);
174 }
175 texture->removeRenderTarget();
176 } else {
177 // TODO: Our CPU stretch doesn't filter. But we create separate
178 // stretched textures when the sampler state is either filtered or
179 // not. Either implement filtered stretch blit on CPU or just create
180 // one when FBO case fails.
181
182 rtDesc.fFlags = 0;
183 // no longer need to clamp at min RT size.
184 rtDesc.fWidth = GrNextPow2(desc.fWidth);
185 rtDesc.fHeight = GrNextPow2(desc.fHeight);
186 int bpp = GrTexture::BytesPerPixel(desc.fFormat);
187 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
188 rtDesc.fWidth *
189 rtDesc.fHeight);
190 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
191 srcData, desc.fWidth, desc.fHeight, bpp);
192
193 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
194
195 GrTexture* texture = fGpu->createTexture(rtDesc,
196 stretchedPixels.get(),
197 stretchedRowBytes);
198 GrAssert(NULL != texture);
199 entry = fTextureCache->createAndLock(*key, texture);
200 }
201 fTextureCache->unlock(clampEntry);
202
203 } else {
204 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
205 if (NULL != texture) {
206 entry = fTextureCache->createAndLock(*key, texture);
207 } else {
208 entry = NULL;
209 }
210 }
211 return entry;
212}
213
214void GrContext::unlockTexture(GrTextureEntry* entry) {
215 fTextureCache->unlock(entry);
216}
217
218void GrContext::detachCachedTexture(GrTextureEntry* entry) {
219 fTextureCache->detach(entry);
220}
221
222void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) {
223 fTextureCache->reattachAndUnlock(entry);
224}
225
226GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc,
227 void* srcData,
228 size_t rowBytes) {
229 return fGpu->createTexture(desc, srcData, rowBytes);
230}
231
reed@google.com01804b42011-01-18 21:50:41 +0000232void GrContext::getTextureCacheLimits(int* maxTextures,
233 size_t* maxTextureBytes) const {
234 fTextureCache->getLimits(maxTextures, maxTextureBytes);
235}
236
237void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
238 fTextureCache->setLimits(maxTextures, maxTextureBytes);
239}
240
reed@google.com02a7e6c2011-01-28 21:21:49 +0000241int GrContext::getMaxTextureDimension() {
242 return fGpu->maxTextureDimension();
243}
244
reed@google.com01804b42011-01-18 21:50:41 +0000245///////////////////////////////////////////////////////////////////////////////
246
bsalomon@google.com8895a7a2011-02-18 16:09:55 +0000247GrRenderTarget* GrContext::createPlatformRenderTarget(
248 intptr_t platformRenderTarget,
249 int stencilBits,
250 int width, int height) {
251 return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits,
reed@google.comac10a2d2010-12-22 21:39:39 +0000252 width, height);
253}
254
255bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
256 int width, int height) {
257 if (!fGpu->supports8BitPalette()) {
258 return false;
259 }
260
bsalomon@google.com0748f212011-02-01 22:56:16 +0000261
reed@google.comac10a2d2010-12-22 21:39:39 +0000262 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
263
bsalomon@google.com0748f212011-02-01 22:56:16 +0000264 if (!isPow2) {
265 if (!fGpu->npotTextureSupport()) {
266 return false;
267 }
268
269 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
270 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
271 if (tiled && !fGpu->npotTextureTileSupport()) {
272 return false;
273 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000274 }
bsalomon@google.com0748f212011-02-01 22:56:16 +0000275 return true;
reed@google.comac10a2d2010-12-22 21:39:39 +0000276}
277
278////////////////////////////////////////////////////////////////////////////////
279
bsalomon@google.com5782d712011-01-21 21:03:59 +0000280void GrContext::setClip(const GrClip& clip) {
281 fGpu->setClip(clip);
282 fGpu->enableState(GrDrawTarget::kClip_StateBit);
283}
284
285void GrContext::setClip(const GrIRect& rect) {
286 GrClip clip;
287 clip.setRect(rect);
288 fGpu->setClip(clip);
289}
290
291////////////////////////////////////////////////////////////////////////////////
292
reed@google.comac10a2d2010-12-22 21:39:39 +0000293void GrContext::eraseColor(GrColor color) {
294 fGpu->eraseColor(color);
295}
296
bsalomon@google.com5782d712011-01-21 21:03:59 +0000297void GrContext::drawPaint(const GrPaint& paint) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000298 // set rect to be big enough to fill the space, but not super-huge, so we
299 // don't overflow fixed-point implementations
300 GrRect r(fGpu->getClip().getBounds());
301 GrMatrix inverse;
302 if (fGpu->getViewInverse(&inverse)) {
303 inverse.mapRect(&r);
304 } else {
305 GrPrintf("---- fGpu->getViewInverse failed\n");
306 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000307 this->drawRect(paint, r);
reed@google.comac10a2d2010-12-22 21:39:39 +0000308}
309
310/* create a triangle strip that strokes the specified triangle. There are 8
311 unique vertices, but we repreat the last 2 to close up. Alternatively we
312 could use an indices array, and then only send 8 verts, but not sure that
313 would be faster.
314 */
315static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
316 GrScalar width) {
317 const GrScalar rad = GrScalarHalf(width);
318
319 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
320 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
321 verts[2].set(rect.fRight - rad, rect.fTop + rad);
322 verts[3].set(rect.fRight + rad, rect.fTop - rad);
323 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
324 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
325 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
326 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
327 verts[8] = verts[0];
328 verts[9] = verts[1];
329}
330
bsalomon@google.com5782d712011-01-21 21:03:59 +0000331void GrContext::drawRect(const GrPaint& paint,
332 const GrRect& rect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000333 GrScalar width,
334 const GrMatrix* matrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000335
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000336 bool textured = NULL != paint.getTexture();
reed@google.comac10a2d2010-12-22 21:39:39 +0000337
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000338 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +0000339
reed@google.comac10a2d2010-12-22 21:39:39 +0000340 if (width >= 0) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000341 // TODO: consider making static vertex buffers for these cases.
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000342 // Hairline could be done by just adding closing vertex to
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000343 // unitSquareVertexBuffer()
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000344 GrVertexLayout layout = (textured) ?
345 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
346 0;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000347 static const int worstCaseVertCount = 10;
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000348 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000349
350 if (!geo.succeeded()) {
351 return;
352 }
353
bsalomon@google.comffca4002011-02-22 20:34:01 +0000354 GrPrimitiveType primType;
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000355 int vertCount;
356 GrPoint* vertex = geo.positions();
357
reed@google.comac10a2d2010-12-22 21:39:39 +0000358 if (width > 0) {
359 vertCount = 10;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000360 primType = kTriangleStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000361 setStrokeRectStrip(vertex, rect, width);
362 } else {
363 // hairline
364 vertCount = 5;
bsalomon@google.comffca4002011-02-22 20:34:01 +0000365 primType = kLineStrip_PrimitiveType;
reed@google.comac10a2d2010-12-22 21:39:39 +0000366 vertex[0].set(rect.fLeft, rect.fTop);
367 vertex[1].set(rect.fRight, rect.fTop);
368 vertex[2].set(rect.fRight, rect.fBottom);
369 vertex[3].set(rect.fLeft, rect.fBottom);
370 vertex[4].set(rect.fLeft, rect.fTop);
371 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000372
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000373 GrDrawTarget::AutoViewMatrixRestore avmr;
374 if (NULL != matrix) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000375 avmr.set(target);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000376 target->preConcatViewMatrix(*matrix);
377 target->preConcatSamplerMatrix(0, *matrix);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000378 }
379
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000380 target->drawNonIndexed(primType, 0, vertCount);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000381 } else {
bsalomon@google.com43333232011-02-02 19:24:54 +0000382 #if GR_STATIC_RECT_VB
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000383 GrVertexLayout layout = (textured) ?
384 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
385 0;
386 target->setVertexSourceToBuffer(layout,
387 fGpu->getUnitSquareVertexBuffer());
388 GrDrawTarget::AutoViewMatrixRestore avmr(target);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000389 GrMatrix m;
390 m.setAll(rect.width(), 0, rect.fLeft,
391 0, rect.height(), rect.fTop,
392 0, 0, GrMatrix::I()[8]);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000393
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000394 if (NULL != matrix) {
395 m.postConcat(*matrix);
396 }
397
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000398 target->preConcatViewMatrix(m);
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000399
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000400 if (textured) {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000401 target->preConcatSamplerMatrix(0, m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000402 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000403 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000404 #else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000405 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000406 #endif
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000407 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000408}
409
bsalomon@google.com5782d712011-01-21 21:03:59 +0000410void GrContext::drawRectToRect(const GrPaint& paint,
411 const GrRect& dstRect,
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000412 const GrRect& srcRect,
413 const GrMatrix* dstMatrix,
414 const GrMatrix* srcMatrix) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000415
416 if (NULL == paint.getTexture()) {
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000417 drawRect(paint, dstRect, -1, dstMatrix);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000418 return;
419 }
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000420
421 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000422
bsalomon@google.com43333232011-02-02 19:24:54 +0000423#if GR_STATIC_RECT_VB
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000424 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
425
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000426 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000427 GrDrawTarget::AutoViewMatrixRestore avmr(target);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000428
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000429 GrMatrix m;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000430
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000431 m.setAll(dstRect.width(), 0, dstRect.fLeft,
432 0, dstRect.height(), dstRect.fTop,
433 0, 0, GrMatrix::I()[8]);
434 if (NULL != dstMatrix) {
435 m.postConcat(*dstMatrix);
436 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000437 target->preConcatViewMatrix(m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000438
439 m.setAll(srcRect.width(), 0, srcRect.fLeft,
440 0, srcRect.height(), srcRect.fTop,
441 0, 0, GrMatrix::I()[8]);
442 if (NULL != srcMatrix) {
443 m.postConcat(*srcMatrix);
444 }
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000445 target->preConcatSamplerMatrix(0, m);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000446
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000447 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
bsalomon@google.comffca4002011-02-22 20:34:01 +0000448 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000449#else
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000450
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000451 GrDrawTarget* target;
452#if BATCH_RECT_TO_RECT
453 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
454#else
455 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com6f7fbc92011-02-01 19:12:40 +0000456#endif
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000457
458 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
459 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
460 srcRects[0] = &srcRect;
461 srcMatrices[0] = srcMatrix;
462
463 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
464#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +0000465}
466
467void GrContext::drawVertices(const GrPaint& paint,
bsalomon@google.comffca4002011-02-22 20:34:01 +0000468 GrPrimitiveType primitiveType,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000469 int vertexCount,
470 const GrPoint positions[],
471 const GrPoint texCoords[],
472 const GrColor colors[],
473 const uint16_t indices[],
474 int indexCount) {
475 GrVertexLayout layout = 0;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000476 int vertexSize = sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000477
478 GrDrawTarget::AutoReleaseGeometry geo;
479
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000480 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000481
482 if (NULL != paint.getTexture()) {
483 if (NULL == texCoords) {
484 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
485 } else {
486 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000487 vertexSize += sizeof(GrPoint);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000488 }
489 }
490
491 if (NULL != colors) {
492 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000493 vertexSize += sizeof(GrColor);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000494 }
495
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000496 if (sizeof(GrPoint) != vertexSize) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000497 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000498 GrPrintf("Failed to get space for vertices!");
499 return;
500 }
501 int texOffsets[GrDrawTarget::kMaxTexCoords];
502 int colorOffset;
503 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
504 texOffsets,
505 &colorOffset);
506 void* curVertex = geo.vertices();
507
508 for (int i = 0; i < vertexCount; ++i) {
509 *((GrPoint*)curVertex) = positions[i];
510
511 if (texOffsets[0] > 0) {
512 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
513 }
514 if (colorOffset > 0) {
515 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
516 }
517 curVertex = (void*)((intptr_t)curVertex + vsize);
518 }
519 } else {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000520 target->setVertexSourceToArray(layout, positions, vertexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000521 }
522
523 if (NULL != indices) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000524 target->setIndexSourceToArray(indices, indexCount);
525 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000526 } else {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000527 target->drawNonIndexed(primitiveType, 0, vertexCount);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000528 }
529}
530
531
reed@google.comac10a2d2010-12-22 21:39:39 +0000532////////////////////////////////////////////////////////////////////////////////
533
bsalomon@google.com5782d712011-01-21 21:03:59 +0000534void GrContext::drawPath(const GrPaint& paint,
535 GrPathIter* path,
bsalomon@google.comffca4002011-02-22 20:34:01 +0000536 GrPathFill fill,
bsalomon@google.com5782d712011-01-21 21:03:59 +0000537 const GrPoint* translate) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000538
reed@google.comac10a2d2010-12-22 21:39:39 +0000539
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000540 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000541
bsalomon@google.comffca4002011-02-22 20:34:01 +0000542 GrDrawTarget::StageBitfield enabledStages = 0;
bsalomon@google.com5782d712011-01-21 21:03:59 +0000543 if (NULL != paint.getTexture()) {
bsalomon@google.comffca4002011-02-22 20:34:01 +0000544 enabledStages |= 1;
reed@google.comac10a2d2010-12-22 21:39:39 +0000545 }
bsalomon@google.comffca4002011-02-22 20:34:01 +0000546 fPathRenderer->drawPath(target, enabledStages, path, fill, translate);
reed@google.comac10a2d2010-12-22 21:39:39 +0000547}
548
bsalomon@google.com5782d712011-01-21 21:03:59 +0000549////////////////////////////////////////////////////////////////////////////////
550
reed@google.comac10a2d2010-12-22 21:39:39 +0000551void GrContext::flush(bool flushRenderTarget) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000552 flushDrawBuffer();
reed@google.comac10a2d2010-12-22 21:39:39 +0000553 if (flushRenderTarget) {
554 fGpu->forceRenderTargetFlush();
555 }
556}
557
558void GrContext::flushText() {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000559 if (kText_DrawCategory == fLastDrawCategory) {
560 flushDrawBuffer();
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000561 }
reed@google.comac10a2d2010-12-22 21:39:39 +0000562}
563
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000564void GrContext::flushDrawBuffer() {
565#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
566 fDrawBuffer->playback(fGpu);
567 fDrawBuffer->reset();
568#endif
569}
570
reed@google.comac10a2d2010-12-22 21:39:39 +0000571bool GrContext::readPixels(int left, int top, int width, int height,
572 GrTexture::PixelConfig config, void* buffer) {
573 this->flush(true);
574 return fGpu->readPixels(left, top, width, height, config, buffer);
575}
576
577void GrContext::writePixels(int left, int top, int width, int height,
578 GrTexture::PixelConfig config, const void* buffer,
579 size_t stride) {
bsalomon@google.com5782d712011-01-21 21:03:59 +0000580
581 // TODO: when underlying api has a direct way to do this we should use it
582 // (e.g. glDrawPixels on desktop GL).
583
reed@google.comac10a2d2010-12-22 21:39:39 +0000584 const GrGpu::TextureDesc desc = {
585 0, GrGpu::kNone_AALevel, width, height, config
586 };
587 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
588 if (NULL == texture) {
589 return;
590 }
591
592 this->flush(true);
593
594 GrAutoUnref aur(texture);
595 GrDrawTarget::AutoStateRestore asr(fGpu);
596
597 GrMatrix matrix;
598 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
599 fGpu->setViewMatrix(matrix);
reed@google.comac10a2d2010-12-22 21:39:39 +0000600
601 fGpu->disableState(GrDrawTarget::kClip_StateBit);
602 fGpu->setAlpha(0xFF);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000603 fGpu->setBlendFunc(kOne_BlendCoeff,
604 kZero_BlendCoeff);
bsalomon@google.com8531c1c2011-01-13 19:52:45 +0000605 fGpu->setTexture(0, texture);
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000606
607 GrSamplerState sampler;
608 sampler.setClampNoFilter();
609 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
610 sampler.setMatrix(matrix);
611 fGpu->setSamplerState(0, sampler);
reed@google.comac10a2d2010-12-22 21:39:39 +0000612
bsalomon@google.com5782d712011-01-21 21:03:59 +0000613 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
614 static const int VCOUNT = 4;
615
616 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
617 if (!geo.succeeded()) {
618 return;
619 }
620 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
bsalomon@google.comffca4002011-02-22 20:34:01 +0000621 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
bsalomon@google.com5782d712011-01-21 21:03:59 +0000622}
623////////////////////////////////////////////////////////////////////////////////
624
625void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
626 target->setTexture(0, paint.getTexture());
bsalomon@google.com5782d712011-01-21 21:03:59 +0000627 target->setSamplerState(0, paint.fSampler);
628 target->setColor(paint.fColor);
629
630 if (paint.fDither) {
631 target->enableState(GrDrawTarget::kDither_StateBit);
632 } else {
633 target->disableState(GrDrawTarget::kDither_StateBit);
634 }
635 if (paint.fAntiAlias) {
636 target->enableState(GrDrawTarget::kAntialias_StateBit);
637 } else {
638 target->disableState(GrDrawTarget::kAntialias_StateBit);
639 }
640 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
641}
642
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000643GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
644 DrawCategory category) {
645 if (category != fLastDrawCategory) {
646 flushDrawBuffer();
647 fLastDrawCategory = category;
648 }
bsalomon@google.com5782d712011-01-21 21:03:59 +0000649 SetPaint(paint, fGpu);
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000650 GrDrawTarget* target = fGpu;
651 switch (category) {
652 case kText_DrawCategory:
653#if DEFER_TEXT_RENDERING
654 target = fDrawBuffer;
655 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
656#else
657 target = fGpu;
658#endif
659 break;
660 case kUnbuffered_DrawCategory:
661 target = fGpu;
662 break;
663 case kBuffered_DrawCategory:
664 target = fDrawBuffer;
665 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
666 break;
667 }
668 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +0000669}
670
671////////////////////////////////////////////////////////////////////////////////
672
reed@google.comac10a2d2010-12-22 21:39:39 +0000673void GrContext::resetContext() {
674 fGpu->resetContext();
675}
676
reed@google.comac10a2d2010-12-22 21:39:39 +0000677void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000678 flush(false);
reed@google.comac10a2d2010-12-22 21:39:39 +0000679 fGpu->setRenderTarget(target);
680}
681
bsalomon@google.com5782d712011-01-21 21:03:59 +0000682GrRenderTarget* GrContext::getRenderTarget() {
683 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +0000684}
685
bsalomon@google.com5782d712011-01-21 21:03:59 +0000686const GrRenderTarget* GrContext::getRenderTarget() const {
687 return fGpu->getRenderTarget();
reed@google.comac10a2d2010-12-22 21:39:39 +0000688}
689
bsalomon@google.com5782d712011-01-21 21:03:59 +0000690const GrMatrix& GrContext::getMatrix() const {
691 return fGpu->getViewMatrix();
reed@google.comac10a2d2010-12-22 21:39:39 +0000692}
693
bsalomon@google.com5782d712011-01-21 21:03:59 +0000694void GrContext::setMatrix(const GrMatrix& m) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000695 fGpu->setViewMatrix(m);
696}
697
bsalomon@google.com5782d712011-01-21 21:03:59 +0000698void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.comc6cf7232011-02-17 16:43:10 +0000699 fGpu->preConcatViewMatrix(m);
reed@google.comac10a2d2010-12-22 21:39:39 +0000700}
701
702static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
703 intptr_t mask = 1 << shift;
704 if (pred) {
705 bits |= mask;
706 } else {
707 bits &= ~mask;
708 }
709 return bits;
710}
711
reed@google.comac10a2d2010-12-22 21:39:39 +0000712void GrContext::resetStats() {
713 fGpu->resetStats();
714}
715
716const GrGpu::Stats& GrContext::getStats() const {
717 return fGpu->getStats();
718}
719
720void GrContext::printStats() const {
721 fGpu->printStats();
722}
723
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000724GrContext::GrContext(GrGpu* gpu) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000725 fGpu = gpu;
726 fGpu->ref();
727 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
728 MAX_TEXTURE_CACHE_BYTES);
729 fFontCache = new GrFontCache(fGpu);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000730
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000731 fLastDrawCategory = kUnbuffered_DrawCategory;
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000732
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000733#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
734 fDrawBufferVBAllocPool =
735 new GrVertexBufferAllocPool(gpu, false,
736 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
737 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
738 fDrawBufferIBAllocPool =
739 new GrIndexBufferAllocPool(gpu, false,
740 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
741 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
742
743 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
744 fDrawBufferIBAllocPool);
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000745#else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000746 fDrawBuffer = NULL;
747 fDrawBufferVBAllocPool = NULL;
748 fDrawBufferIBAllocPool = NULL;
749#endif
750
751#if BATCH_RECT_TO_RECT
752 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
bsalomon@google.com1c13c962011-02-14 16:51:21 +0000753#endif
bsalomon@google.comffca4002011-02-22 20:34:01 +0000754 fPathRenderer = new GrDefaultPathRenderer(fGpu->supportsSingleStencilPassWinding());
reed@google.comac10a2d2010-12-22 21:39:39 +0000755}
756
757bool GrContext::finalizeTextureKey(GrTextureKey* key,
758 const GrSamplerState& sampler) const {
759 uint32_t bits = 0;
760 uint16_t width = key->width();
761 uint16_t height = key->height();
bsalomon@google.com7acdb8e2011-02-11 14:07:02 +0000762
bsalomon@google.com0748f212011-02-01 22:56:16 +0000763
764 if (!fGpu->npotTextureTileSupport()) {
765 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
766
767 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
768 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
769
770 if (tiled && !isPow2) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000771 bits |= 1;
772 bits |= sampler.isFilter() ? 2 : 0;
773 }
774 }
775 key->finalize(bits);
776 return 0 != bits;
777}
778
bsalomon@google.com5782d712011-01-21 21:03:59 +0000779GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
780 GrDrawTarget* target;
reed@google.comac10a2d2010-12-22 21:39:39 +0000781#if DEFER_TEXT_RENDERING
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000782 target = prepareToDraw(paint, kText_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +0000783#else
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000784 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
reed@google.comac10a2d2010-12-22 21:39:39 +0000785#endif
bsalomon@google.com5782d712011-01-21 21:03:59 +0000786 SetPaint(paint, target);
787 return target;
reed@google.comac10a2d2010-12-22 21:39:39 +0000788}
789
bsalomon@google.com86afc2a2011-02-16 16:12:19 +0000790const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
791 return fGpu->getQuadIndexBuffer();
reed@google.comac10a2d2010-12-22 21:39:39 +0000792}