blob: 8017f73eba19caa4179f4551d4a3f92309bc3c30 [file] [log] [blame]
bsalomon@google.com27847de2011-02-22 20:59:41 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
bsalomon@google.com27847de2011-02-22 20:59:41 +00003
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
17#include "GrContext.h"
18#include "GrTypes.h"
19#include "GrTextureCache.h"
20#include "GrTextStrike.h"
21#include "GrMemory.h"
22#include "GrPathIter.h"
23#include "GrClipIterator.h"
24#include "GrIndexBuffer.h"
25#include "GrInOrderDrawBuffer.h"
26#include "GrBufferAllocPool.h"
27#include "GrPathRenderer.h"
28
29#define DEFER_TEXT_RENDERING 1
30
31#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
32
33static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
34static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
35
36static 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;
43
44GrContext* GrContext::Create(GrGpu::Engine engine,
45 GrGpu::Platform3DContext context3D) {
46 GrContext* ctx = NULL;
47 GrGpu* fGpu = GrGpu::Create(engine, context3D);
48 if (NULL != fGpu) {
49 ctx = new GrContext(fGpu);
50 fGpu->unref();
51 }
52 return ctx;
53}
54
55GrContext* GrContext::CreateGLShaderContext() {
56 return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL);
57}
58
59GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000060 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000061 fGpu->unref();
62 delete fTextureCache;
63 delete fFontCache;
64 delete fDrawBuffer;
65 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000066 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000067 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +000068}
69
bsalomon@google.com8fe72472011-03-30 21:26:44 +000070void GrContext::contextLost() {
71 delete fDrawBuffer;
72 fDrawBuffer = NULL;
73 delete fDrawBufferVBAllocPool;
74 fDrawBufferVBAllocPool = NULL;
75 delete fDrawBufferIBAllocPool;
76 fDrawBufferIBAllocPool = NULL;
77
78 fTextureCache->removeAll();
79 fFontCache->freeAll();
80 fGpu->markContextDirty();
81
82 fGpu->abandonResources();
83
84 this->setupDrawBuffer();
85}
86
87void GrContext::resetContext() {
88 fGpu->markContextDirty();
89}
90
91void GrContext::freeGpuResources() {
92 this->flush();
93 fTextureCache->removeAll();
94 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +000095}
96
97GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
98 const GrSamplerState& sampler) {
99 finalizeTextureKey(key, sampler);
100 return fTextureCache->findAndLock(*key);
101}
102
103static void stretchImage(void* dst,
104 int dstW,
105 int dstH,
106 void* src,
107 int srcW,
108 int srcH,
109 int bpp) {
110 GrFixed dx = (srcW << 16) / dstW;
111 GrFixed dy = (srcH << 16) / dstH;
112
113 GrFixed y = dy >> 1;
114
115 int dstXLimit = dstW*bpp;
116 for (int j = 0; j < dstH; ++j) {
117 GrFixed x = dx >> 1;
118 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
119 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
120 for (int i = 0; i < dstXLimit; i += bpp) {
121 memcpy((uint8_t*) dstRow + i,
122 (uint8_t*) srcRow + (x>>16)*bpp,
123 bpp);
124 x += dx;
125 }
126 y += dy;
127 }
128}
129
130GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
131 const GrSamplerState& sampler,
132 const GrGpu::TextureDesc& desc,
133 void* srcData, size_t rowBytes) {
134 GrAssert(key->width() == desc.fWidth);
135 GrAssert(key->height() == desc.fHeight);
136
137#if GR_DUMP_TEXTURE_UPLOAD
138 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
139#endif
140
141 GrTextureEntry* entry = NULL;
142 bool special = finalizeTextureKey(key, sampler);
143 if (special) {
144 GrTextureEntry* clampEntry;
145 GrTextureKey clampKey(*key);
146 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
147
148 if (NULL == clampEntry) {
149 clampEntry = createAndLockTexture(&clampKey,
150 GrSamplerState::ClampNoFilter(),
151 desc, srcData, rowBytes);
152 GrAssert(NULL != clampEntry);
153 if (NULL == clampEntry) {
154 return NULL;
155 }
156 }
157 GrGpu::TextureDesc rtDesc = desc;
158 rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag |
bsalomon@google.comf6a7c112011-03-24 16:14:10 +0000159 GrGpu::kNoStencil_TextureFlag;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000160 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
161 fGpu->minRenderTargetWidth()));
162 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
163 fGpu->minRenderTargetHeight()));
164
165 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
166
167 if (NULL != texture) {
168 GrDrawTarget::AutoStateRestore asr(fGpu);
169 fGpu->setRenderTarget(texture->asRenderTarget());
170 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000171 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000172 fGpu->setViewMatrix(GrMatrix::I());
173 fGpu->setAlpha(0xff);
174 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
175 fGpu->disableState(GrDrawTarget::kDither_StateBit |
176 GrDrawTarget::kClip_StateBit |
177 GrDrawTarget::kAntialias_StateBit);
178 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
179 GrSamplerState::kClamp_WrapMode,
180 sampler.isFilter());
181 fGpu->setSamplerState(0, stretchSampler);
182
183 static const GrVertexLayout layout =
184 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
185 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
186
187 if (arg.succeeded()) {
188 GrPoint* verts = (GrPoint*) arg.vertices();
189 verts[0].setIRectFan(0, 0,
190 texture->width(),
191 texture->height(),
192 2*sizeof(GrPoint));
193 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
194 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
195 0, 4);
196 entry = fTextureCache->createAndLock(*key, texture);
197 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000198 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000199 } else {
200 // TODO: Our CPU stretch doesn't filter. But we create separate
201 // stretched textures when the sampler state is either filtered or
202 // not. Either implement filtered stretch blit on CPU or just create
203 // one when FBO case fails.
204
205 rtDesc.fFlags = 0;
206 // no longer need to clamp at min RT size.
207 rtDesc.fWidth = GrNextPow2(desc.fWidth);
208 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000209 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000210 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
211 rtDesc.fWidth *
212 rtDesc.fHeight);
213 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
214 srcData, desc.fWidth, desc.fHeight, bpp);
215
216 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
217
218 GrTexture* texture = fGpu->createTexture(rtDesc,
219 stretchedPixels.get(),
220 stretchedRowBytes);
221 GrAssert(NULL != texture);
222 entry = fTextureCache->createAndLock(*key, texture);
223 }
224 fTextureCache->unlock(clampEntry);
225
226 } else {
227 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
228 if (NULL != texture) {
229 entry = fTextureCache->createAndLock(*key, texture);
230 } else {
231 entry = NULL;
232 }
233 }
234 return entry;
235}
236
237void GrContext::unlockTexture(GrTextureEntry* entry) {
238 fTextureCache->unlock(entry);
239}
240
241void GrContext::detachCachedTexture(GrTextureEntry* entry) {
242 fTextureCache->detach(entry);
243}
244
245void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) {
246 fTextureCache->reattachAndUnlock(entry);
247}
248
249GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc,
250 void* srcData,
251 size_t rowBytes) {
252 return fGpu->createTexture(desc, srcData, rowBytes);
253}
254
255void GrContext::getTextureCacheLimits(int* maxTextures,
256 size_t* maxTextureBytes) const {
257 fTextureCache->getLimits(maxTextures, maxTextureBytes);
258}
259
260void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
261 fTextureCache->setLimits(maxTextures, maxTextureBytes);
262}
263
264int GrContext::getMaxTextureDimension() {
265 return fGpu->maxTextureDimension();
266}
267
268///////////////////////////////////////////////////////////////////////////////
269
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000270GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
271 // validate flags here so that GrGpu subclasses don't have to check
272 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
273 0 != desc.fRenderTargetFlags) {
274 return NULL;
275 }
276 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
277 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
278 return NULL;
279 }
280 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
281 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
282 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
283 return NULL;
284 }
285 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000286}
287
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000288///////////////////////////////////////////////////////////////////////////////
289
bsalomon@google.com27847de2011-02-22 20:59:41 +0000290bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
291 int width, int height) {
292 if (!fGpu->supports8BitPalette()) {
293 return false;
294 }
295
296
297 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
298
299 if (!isPow2) {
300 if (!fGpu->npotTextureSupport()) {
301 return false;
302 }
303
304 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
305 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
306 if (tiled && !fGpu->npotTextureTileSupport()) {
307 return false;
308 }
309 }
310 return true;
311}
312
313////////////////////////////////////////////////////////////////////////////////
314
315void GrContext::setClip(const GrClip& clip) {
316 fGpu->setClip(clip);
317 fGpu->enableState(GrDrawTarget::kClip_StateBit);
318}
319
320void GrContext::setClip(const GrIRect& rect) {
321 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000322 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000323 fGpu->setClip(clip);
324}
325
326////////////////////////////////////////////////////////////////////////////////
327
328void GrContext::eraseColor(GrColor color) {
329 fGpu->eraseColor(color);
330}
331
332void GrContext::drawPaint(const GrPaint& paint) {
333 // set rect to be big enough to fill the space, but not super-huge, so we
334 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000335 GrRect r;
336 r.setLTRB(0, 0,
337 GrIntToScalar(getRenderTarget()->width()),
338 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000339 GrMatrix inverse;
340 if (fGpu->getViewInverse(&inverse)) {
341 inverse.mapRect(&r);
342 } else {
343 GrPrintf("---- fGpu->getViewInverse failed\n");
344 }
345 this->drawRect(paint, r);
346}
347
348/* create a triangle strip that strokes the specified triangle. There are 8
349 unique vertices, but we repreat the last 2 to close up. Alternatively we
350 could use an indices array, and then only send 8 verts, but not sure that
351 would be faster.
352 */
353static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
354 GrScalar width) {
355 const GrScalar rad = GrScalarHalf(width);
356
357 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
358 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
359 verts[2].set(rect.fRight - rad, rect.fTop + rad);
360 verts[3].set(rect.fRight + rad, rect.fTop - rad);
361 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
362 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
363 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
364 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
365 verts[8] = verts[0];
366 verts[9] = verts[1];
367}
368
369void GrContext::drawRect(const GrPaint& paint,
370 const GrRect& rect,
371 GrScalar width,
372 const GrMatrix* matrix) {
373
374 bool textured = NULL != paint.getTexture();
375
376 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
377
378 if (width >= 0) {
379 // TODO: consider making static vertex buffers for these cases.
380 // Hairline could be done by just adding closing vertex to
381 // unitSquareVertexBuffer()
382 GrVertexLayout layout = (textured) ?
383 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
384 0;
385 static const int worstCaseVertCount = 10;
386 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
387
388 if (!geo.succeeded()) {
389 return;
390 }
391
392 GrPrimitiveType primType;
393 int vertCount;
394 GrPoint* vertex = geo.positions();
395
396 if (width > 0) {
397 vertCount = 10;
398 primType = kTriangleStrip_PrimitiveType;
399 setStrokeRectStrip(vertex, rect, width);
400 } else {
401 // hairline
402 vertCount = 5;
403 primType = kLineStrip_PrimitiveType;
404 vertex[0].set(rect.fLeft, rect.fTop);
405 vertex[1].set(rect.fRight, rect.fTop);
406 vertex[2].set(rect.fRight, rect.fBottom);
407 vertex[3].set(rect.fLeft, rect.fBottom);
408 vertex[4].set(rect.fLeft, rect.fTop);
409 }
410
411 GrDrawTarget::AutoViewMatrixRestore avmr;
412 if (NULL != matrix) {
413 avmr.set(target);
414 target->preConcatViewMatrix(*matrix);
415 target->preConcatSamplerMatrix(0, *matrix);
416 }
417
418 target->drawNonIndexed(primType, 0, vertCount);
419 } else {
420 #if GR_STATIC_RECT_VB
421 GrVertexLayout layout = (textured) ?
422 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
423 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000424 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000425 fGpu->getUnitSquareVertexBuffer());
426 GrDrawTarget::AutoViewMatrixRestore avmr(target);
427 GrMatrix m;
428 m.setAll(rect.width(), 0, rect.fLeft,
429 0, rect.height(), rect.fTop,
430 0, 0, GrMatrix::I()[8]);
431
432 if (NULL != matrix) {
433 m.postConcat(*matrix);
434 }
435
436 target->preConcatViewMatrix(m);
437
438 if (textured) {
439 target->preConcatSamplerMatrix(0, m);
440 }
441 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
442 #else
443 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
444 #endif
445 }
446}
447
448void GrContext::drawRectToRect(const GrPaint& paint,
449 const GrRect& dstRect,
450 const GrRect& srcRect,
451 const GrMatrix* dstMatrix,
452 const GrMatrix* srcMatrix) {
453
454 if (NULL == paint.getTexture()) {
455 drawRect(paint, dstRect, -1, dstMatrix);
456 return;
457 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000458
bsalomon@google.com27847de2011-02-22 20:59:41 +0000459 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
460
461#if GR_STATIC_RECT_VB
462 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
463
464 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
465 GrDrawTarget::AutoViewMatrixRestore avmr(target);
466
467 GrMatrix m;
468
469 m.setAll(dstRect.width(), 0, dstRect.fLeft,
470 0, dstRect.height(), dstRect.fTop,
471 0, 0, GrMatrix::I()[8]);
472 if (NULL != dstMatrix) {
473 m.postConcat(*dstMatrix);
474 }
475 target->preConcatViewMatrix(m);
476
477 m.setAll(srcRect.width(), 0, srcRect.fLeft,
478 0, srcRect.height(), srcRect.fTop,
479 0, 0, GrMatrix::I()[8]);
480 if (NULL != srcMatrix) {
481 m.postConcat(*srcMatrix);
482 }
483 target->preConcatSamplerMatrix(0, m);
484
485 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
486 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
487#else
488
489 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000490#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +0000491 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000492#else
bsalomon@google.com27847de2011-02-22 20:59:41 +0000493 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
494#endif
495
496 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
497 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
498 srcRects[0] = &srcRect;
499 srcMatrices[0] = srcMatrix;
500
501 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
502#endif
503}
504
505void GrContext::drawVertices(const GrPaint& paint,
506 GrPrimitiveType primitiveType,
507 int vertexCount,
508 const GrPoint positions[],
509 const GrPoint texCoords[],
510 const GrColor colors[],
511 const uint16_t indices[],
512 int indexCount) {
513 GrVertexLayout layout = 0;
514 int vertexSize = sizeof(GrPoint);
515
516 GrDrawTarget::AutoReleaseGeometry geo;
517
518 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
519
520 if (NULL != paint.getTexture()) {
521 if (NULL == texCoords) {
522 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
523 } else {
524 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
525 vertexSize += sizeof(GrPoint);
526 }
527 }
528
529 if (NULL != colors) {
530 layout |= GrDrawTarget::kColor_VertexLayoutBit;
531 vertexSize += sizeof(GrColor);
532 }
533
534 if (sizeof(GrPoint) != vertexSize) {
535 if (!geo.set(target, layout, vertexCount, 0)) {
536 GrPrintf("Failed to get space for vertices!");
537 return;
538 }
539 int texOffsets[GrDrawTarget::kMaxTexCoords];
540 int colorOffset;
541 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
542 texOffsets,
543 &colorOffset);
544 void* curVertex = geo.vertices();
545
546 for (int i = 0; i < vertexCount; ++i) {
547 *((GrPoint*)curVertex) = positions[i];
548
549 if (texOffsets[0] > 0) {
550 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
551 }
552 if (colorOffset > 0) {
553 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
554 }
555 curVertex = (void*)((intptr_t)curVertex + vsize);
556 }
557 } else {
558 target->setVertexSourceToArray(layout, positions, vertexCount);
559 }
560
561 if (NULL != indices) {
562 target->setIndexSourceToArray(indices, indexCount);
563 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
564 } else {
565 target->drawNonIndexed(primitiveType, 0, vertexCount);
566 }
567}
568
569
570////////////////////////////////////////////////////////////////////////////////
571
572void GrContext::drawPath(const GrPaint& paint,
573 GrPathIter* path,
574 GrPathFill fill,
575 const GrPoint* translate) {
576
577
578 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
579
580 GrDrawTarget::StageBitfield enabledStages = 0;
581 if (NULL != paint.getTexture()) {
582 enabledStages |= 1;
583 }
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000584 GrPathRenderer* pr = getPathRenderer(target, path, fill);
585 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000586}
587
bsalomon@google.comd302f142011-03-03 13:54:13 +0000588void GrContext::drawPath(const GrPaint& paint,
589 const GrPath& path,
590 GrPathFill fill,
591 const GrPoint* translate) {
592 GrPath::Iter iter(path);
593 this->drawPath(paint, &iter, fill, translate);
594}
595
596
bsalomon@google.com27847de2011-02-22 20:59:41 +0000597////////////////////////////////////////////////////////////////////////////////
598
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000599void GrContext::flush(int flagsBitfield) {
600 if (kDiscard_FlushBit & flagsBitfield) {
601 fDrawBuffer->reset();
602 } else {
603 flushDrawBuffer();
604 }
605
606 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000607 fGpu->forceRenderTargetFlush();
608 }
609}
610
611void GrContext::flushText() {
612 if (kText_DrawCategory == fLastDrawCategory) {
613 flushDrawBuffer();
614 }
615}
616
617void GrContext::flushDrawBuffer() {
618#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
619 fDrawBuffer->playback(fGpu);
620 fDrawBuffer->reset();
621#endif
622}
623
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000624bool GrContext::readTexturePixels(GrTexture* texture,
625 int left, int top, int width, int height,
626 GrPixelConfig config, void* buffer) {
627
628 // TODO: code read pixels for textures that aren't rendertargets
629
630 this->flush();
631 GrRenderTarget* target = texture->asRenderTarget();
632 if (NULL != target) {
633 return fGpu->readPixels(target,
634 left, top, width, height,
635 config, buffer);
636 } else {
637 return false;
638 }
639}
640
641bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
642 int left, int top, int width, int height,
643 GrPixelConfig config, void* buffer) {
644 uint32_t flushFlags = 0;
645 if (NULL == target) {
646 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
647 }
648
649 this->flush(flushFlags);
650 return fGpu->readPixels(target,
651 left, top, width, height,
652 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000653}
654
655void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000656 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000657 size_t stride) {
658
659 // TODO: when underlying api has a direct way to do this we should use it
660 // (e.g. glDrawPixels on desktop GL).
661
662 const GrGpu::TextureDesc desc = {
663 0, GrGpu::kNone_AALevel, width, height, config
664 };
665 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
666 if (NULL == texture) {
667 return;
668 }
669
670 this->flush(true);
671
672 GrAutoUnref aur(texture);
673 GrDrawTarget::AutoStateRestore asr(fGpu);
674
675 GrMatrix matrix;
676 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
677 fGpu->setViewMatrix(matrix);
678
679 fGpu->disableState(GrDrawTarget::kClip_StateBit);
680 fGpu->setAlpha(0xFF);
681 fGpu->setBlendFunc(kOne_BlendCoeff,
682 kZero_BlendCoeff);
683 fGpu->setTexture(0, texture);
684
685 GrSamplerState sampler;
686 sampler.setClampNoFilter();
687 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
688 sampler.setMatrix(matrix);
689 fGpu->setSamplerState(0, sampler);
690
691 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
692 static const int VCOUNT = 4;
693
694 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
695 if (!geo.succeeded()) {
696 return;
697 }
698 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
699 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
700}
701////////////////////////////////////////////////////////////////////////////////
702
703void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
704 target->setTexture(0, paint.getTexture());
705 target->setSamplerState(0, paint.fSampler);
706 target->setColor(paint.fColor);
707
708 if (paint.fDither) {
709 target->enableState(GrDrawTarget::kDither_StateBit);
710 } else {
711 target->disableState(GrDrawTarget::kDither_StateBit);
712 }
713 if (paint.fAntiAlias) {
714 target->enableState(GrDrawTarget::kAntialias_StateBit);
715 } else {
716 target->disableState(GrDrawTarget::kAntialias_StateBit);
717 }
718 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
719}
720
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000721GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000722 DrawCategory category) {
723 if (category != fLastDrawCategory) {
724 flushDrawBuffer();
725 fLastDrawCategory = category;
726 }
727 SetPaint(paint, fGpu);
728 GrDrawTarget* target = fGpu;
729 switch (category) {
730 case kText_DrawCategory:
731#if DEFER_TEXT_RENDERING
732 target = fDrawBuffer;
733 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
734#else
735 target = fGpu;
736#endif
737 break;
738 case kUnbuffered_DrawCategory:
739 target = fGpu;
740 break;
741 case kBuffered_DrawCategory:
742 target = fDrawBuffer;
743 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
744 break;
745 }
746 return target;
747}
748
749////////////////////////////////////////////////////////////////////////////////
750
bsalomon@google.com27847de2011-02-22 20:59:41 +0000751void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000752 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000753 fGpu->setRenderTarget(target);
754}
755
756GrRenderTarget* GrContext::getRenderTarget() {
757 return fGpu->getRenderTarget();
758}
759
760const GrRenderTarget* GrContext::getRenderTarget() const {
761 return fGpu->getRenderTarget();
762}
763
764const GrMatrix& GrContext::getMatrix() const {
765 return fGpu->getViewMatrix();
766}
767
768void GrContext::setMatrix(const GrMatrix& m) {
769 fGpu->setViewMatrix(m);
770}
771
772void GrContext::concatMatrix(const GrMatrix& m) const {
773 fGpu->preConcatViewMatrix(m);
774}
775
776static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
777 intptr_t mask = 1 << shift;
778 if (pred) {
779 bits |= mask;
780 } else {
781 bits &= ~mask;
782 }
783 return bits;
784}
785
786void GrContext::resetStats() {
787 fGpu->resetStats();
788}
789
790const GrGpu::Stats& GrContext::getStats() const {
791 return fGpu->getStats();
792}
793
794void GrContext::printStats() const {
795 fGpu->printStats();
796}
797
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000798GrContext::GrContext(GrGpu* gpu) :
799 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
800 gpu->supportsStencilWrapOps()) {
801
bsalomon@google.com27847de2011-02-22 20:59:41 +0000802 fGpu = gpu;
803 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000804 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000805
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000806 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
807 fGpu->setClipPathRenderer(fCustomPathRenderer);
808
bsalomon@google.com27847de2011-02-22 20:59:41 +0000809 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
810 MAX_TEXTURE_CACHE_BYTES);
811 fFontCache = new GrFontCache(fGpu);
812
813 fLastDrawCategory = kUnbuffered_DrawCategory;
814
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000815 fDrawBuffer = NULL;
816 fDrawBufferVBAllocPool = NULL;
817 fDrawBufferIBAllocPool = NULL;
818
819 this->setupDrawBuffer();
820}
821
822void GrContext::setupDrawBuffer() {
823
824 GrAssert(NULL == fDrawBuffer);
825 GrAssert(NULL == fDrawBufferVBAllocPool);
826 GrAssert(NULL == fDrawBufferIBAllocPool);
827
bsalomon@google.com27847de2011-02-22 20:59:41 +0000828#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000829 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000830 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000831 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
832 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000833 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000834 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000835 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000836 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
837
838 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
839 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000840#endif
841
842#if BATCH_RECT_TO_RECT
843 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
844#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +0000845}
846
847bool GrContext::finalizeTextureKey(GrTextureKey* key,
848 const GrSamplerState& sampler) const {
849 uint32_t bits = 0;
850 uint16_t width = key->width();
851 uint16_t height = key->height();
852
853
854 if (!fGpu->npotTextureTileSupport()) {
855 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
856
857 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
858 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
859
860 if (tiled && !isPow2) {
861 bits |= 1;
862 bits |= sampler.isFilter() ? 2 : 0;
863 }
864 }
865 key->finalize(bits);
866 return 0 != bits;
867}
868
869GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
870 GrDrawTarget* target;
871#if DEFER_TEXT_RENDERING
872 target = prepareToDraw(paint, kText_DrawCategory);
873#else
874 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
875#endif
876 SetPaint(paint, target);
877 return target;
878}
879
880const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
881 return fGpu->getQuadIndexBuffer();
882}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000883
884GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
885 GrPathIter* path,
886 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000887 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000888 fCustomPathRenderer->canDrawPath(target, path, fill)) {
889 return fCustomPathRenderer;
890 } else {
891 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
892 return &fDefaultPathRenderer;
893 }
894}