blob: f6009f55ae58591a31bd73d705f81ec02df46d90 [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() {
60 fGpu->unref();
61 delete fTextureCache;
62 delete fFontCache;
63 delete fDrawBuffer;
64 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000065 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000066 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +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 }
134 GrGpu::TextureDesc rtDesc = desc;
135 rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag |
bsalomon@google.comf6a7c112011-03-24 16:14:10 +0000136 GrGpu::kNoStencil_TextureFlag;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000137 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) {
145 GrDrawTarget::AutoStateRestore asr(fGpu);
146 fGpu->setRenderTarget(texture->asRenderTarget());
147 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000148 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000149 fGpu->setViewMatrix(GrMatrix::I());
150 fGpu->setAlpha(0xff);
151 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
152 fGpu->disableState(GrDrawTarget::kDither_StateBit |
153 GrDrawTarget::kClip_StateBit |
154 GrDrawTarget::kAntialias_StateBit);
155 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
156 GrSamplerState::kClamp_WrapMode,
157 sampler.isFilter());
158 fGpu->setSamplerState(0, stretchSampler);
159
160 static const GrVertexLayout layout =
161 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
162 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
163
164 if (arg.succeeded()) {
165 GrPoint* verts = (GrPoint*) arg.vertices();
166 verts[0].setIRectFan(0, 0,
167 texture->width(),
168 texture->height(),
169 2*sizeof(GrPoint));
170 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
171 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
172 0, 4);
173 entry = fTextureCache->createAndLock(*key, texture);
174 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000175 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000176 } 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
232void 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
241int GrContext::getMaxTextureDimension() {
242 return fGpu->maxTextureDimension();
243}
244
245///////////////////////////////////////////////////////////////////////////////
246
247GrRenderTarget* GrContext::createPlatformRenderTarget(
248 intptr_t platformRenderTarget,
249 int stencilBits,
250 int width, int height) {
251 return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits,
252 width, height);
253}
254
255bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
256 int width, int height) {
257 if (!fGpu->supports8BitPalette()) {
258 return false;
259 }
260
261
262 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
263
264 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 }
274 }
275 return true;
276}
277
278////////////////////////////////////////////////////////////////////////////////
279
280void 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;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000287 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000288 fGpu->setClip(clip);
289}
290
291////////////////////////////////////////////////////////////////////////////////
292
293void GrContext::eraseColor(GrColor color) {
294 fGpu->eraseColor(color);
295}
296
297void GrContext::drawPaint(const GrPaint& paint) {
298 // set rect to be big enough to fill the space, but not super-huge, so we
299 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000300 GrRect r;
301 r.setLTRB(0, 0,
302 GrIntToScalar(getRenderTarget()->width()),
303 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000304 GrMatrix inverse;
305 if (fGpu->getViewInverse(&inverse)) {
306 inverse.mapRect(&r);
307 } else {
308 GrPrintf("---- fGpu->getViewInverse failed\n");
309 }
310 this->drawRect(paint, r);
311}
312
313/* create a triangle strip that strokes the specified triangle. There are 8
314 unique vertices, but we repreat the last 2 to close up. Alternatively we
315 could use an indices array, and then only send 8 verts, but not sure that
316 would be faster.
317 */
318static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
319 GrScalar width) {
320 const GrScalar rad = GrScalarHalf(width);
321
322 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
323 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
324 verts[2].set(rect.fRight - rad, rect.fTop + rad);
325 verts[3].set(rect.fRight + rad, rect.fTop - rad);
326 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
327 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
328 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
329 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
330 verts[8] = verts[0];
331 verts[9] = verts[1];
332}
333
334void GrContext::drawRect(const GrPaint& paint,
335 const GrRect& rect,
336 GrScalar width,
337 const GrMatrix* matrix) {
338
339 bool textured = NULL != paint.getTexture();
340
341 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
342
343 if (width >= 0) {
344 // TODO: consider making static vertex buffers for these cases.
345 // Hairline could be done by just adding closing vertex to
346 // unitSquareVertexBuffer()
347 GrVertexLayout layout = (textured) ?
348 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
349 0;
350 static const int worstCaseVertCount = 10;
351 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
352
353 if (!geo.succeeded()) {
354 return;
355 }
356
357 GrPrimitiveType primType;
358 int vertCount;
359 GrPoint* vertex = geo.positions();
360
361 if (width > 0) {
362 vertCount = 10;
363 primType = kTriangleStrip_PrimitiveType;
364 setStrokeRectStrip(vertex, rect, width);
365 } else {
366 // hairline
367 vertCount = 5;
368 primType = kLineStrip_PrimitiveType;
369 vertex[0].set(rect.fLeft, rect.fTop);
370 vertex[1].set(rect.fRight, rect.fTop);
371 vertex[2].set(rect.fRight, rect.fBottom);
372 vertex[3].set(rect.fLeft, rect.fBottom);
373 vertex[4].set(rect.fLeft, rect.fTop);
374 }
375
376 GrDrawTarget::AutoViewMatrixRestore avmr;
377 if (NULL != matrix) {
378 avmr.set(target);
379 target->preConcatViewMatrix(*matrix);
380 target->preConcatSamplerMatrix(0, *matrix);
381 }
382
383 target->drawNonIndexed(primType, 0, vertCount);
384 } else {
385 #if GR_STATIC_RECT_VB
386 GrVertexLayout layout = (textured) ?
387 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
388 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000389 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000390 fGpu->getUnitSquareVertexBuffer());
391 GrDrawTarget::AutoViewMatrixRestore avmr(target);
392 GrMatrix m;
393 m.setAll(rect.width(), 0, rect.fLeft,
394 0, rect.height(), rect.fTop,
395 0, 0, GrMatrix::I()[8]);
396
397 if (NULL != matrix) {
398 m.postConcat(*matrix);
399 }
400
401 target->preConcatViewMatrix(m);
402
403 if (textured) {
404 target->preConcatSamplerMatrix(0, m);
405 }
406 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
407 #else
408 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
409 #endif
410 }
411}
412
413void GrContext::drawRectToRect(const GrPaint& paint,
414 const GrRect& dstRect,
415 const GrRect& srcRect,
416 const GrMatrix* dstMatrix,
417 const GrMatrix* srcMatrix) {
418
419 if (NULL == paint.getTexture()) {
420 drawRect(paint, dstRect, -1, dstMatrix);
421 return;
422 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000423
bsalomon@google.com27847de2011-02-22 20:59:41 +0000424 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
425
426#if GR_STATIC_RECT_VB
427 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
428
429 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
430 GrDrawTarget::AutoViewMatrixRestore avmr(target);
431
432 GrMatrix m;
433
434 m.setAll(dstRect.width(), 0, dstRect.fLeft,
435 0, dstRect.height(), dstRect.fTop,
436 0, 0, GrMatrix::I()[8]);
437 if (NULL != dstMatrix) {
438 m.postConcat(*dstMatrix);
439 }
440 target->preConcatViewMatrix(m);
441
442 m.setAll(srcRect.width(), 0, srcRect.fLeft,
443 0, srcRect.height(), srcRect.fTop,
444 0, 0, GrMatrix::I()[8]);
445 if (NULL != srcMatrix) {
446 m.postConcat(*srcMatrix);
447 }
448 target->preConcatSamplerMatrix(0, m);
449
450 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
451 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
452#else
453
454 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000455#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +0000456 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000457#else
bsalomon@google.com27847de2011-02-22 20:59:41 +0000458 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
459#endif
460
461 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
462 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
463 srcRects[0] = &srcRect;
464 srcMatrices[0] = srcMatrix;
465
466 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
467#endif
468}
469
470void GrContext::drawVertices(const GrPaint& paint,
471 GrPrimitiveType primitiveType,
472 int vertexCount,
473 const GrPoint positions[],
474 const GrPoint texCoords[],
475 const GrColor colors[],
476 const uint16_t indices[],
477 int indexCount) {
478 GrVertexLayout layout = 0;
479 int vertexSize = sizeof(GrPoint);
480
481 GrDrawTarget::AutoReleaseGeometry geo;
482
483 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
484
485 if (NULL != paint.getTexture()) {
486 if (NULL == texCoords) {
487 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
488 } else {
489 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
490 vertexSize += sizeof(GrPoint);
491 }
492 }
493
494 if (NULL != colors) {
495 layout |= GrDrawTarget::kColor_VertexLayoutBit;
496 vertexSize += sizeof(GrColor);
497 }
498
499 if (sizeof(GrPoint) != vertexSize) {
500 if (!geo.set(target, layout, vertexCount, 0)) {
501 GrPrintf("Failed to get space for vertices!");
502 return;
503 }
504 int texOffsets[GrDrawTarget::kMaxTexCoords];
505 int colorOffset;
506 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
507 texOffsets,
508 &colorOffset);
509 void* curVertex = geo.vertices();
510
511 for (int i = 0; i < vertexCount; ++i) {
512 *((GrPoint*)curVertex) = positions[i];
513
514 if (texOffsets[0] > 0) {
515 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
516 }
517 if (colorOffset > 0) {
518 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
519 }
520 curVertex = (void*)((intptr_t)curVertex + vsize);
521 }
522 } else {
523 target->setVertexSourceToArray(layout, positions, vertexCount);
524 }
525
526 if (NULL != indices) {
527 target->setIndexSourceToArray(indices, indexCount);
528 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
529 } else {
530 target->drawNonIndexed(primitiveType, 0, vertexCount);
531 }
532}
533
534
535////////////////////////////////////////////////////////////////////////////////
536
537void GrContext::drawPath(const GrPaint& paint,
538 GrPathIter* path,
539 GrPathFill fill,
540 const GrPoint* translate) {
541
542
543 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
544
545 GrDrawTarget::StageBitfield enabledStages = 0;
546 if (NULL != paint.getTexture()) {
547 enabledStages |= 1;
548 }
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000549 GrPathRenderer* pr = getPathRenderer(target, path, fill);
550 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000551}
552
bsalomon@google.comd302f142011-03-03 13:54:13 +0000553void GrContext::drawPath(const GrPaint& paint,
554 const GrPath& path,
555 GrPathFill fill,
556 const GrPoint* translate) {
557 GrPath::Iter iter(path);
558 this->drawPath(paint, &iter, fill, translate);
559}
560
561
bsalomon@google.com27847de2011-02-22 20:59:41 +0000562////////////////////////////////////////////////////////////////////////////////
563
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000564void GrContext::flush(int flagsBitfield) {
565 if (kDiscard_FlushBit & flagsBitfield) {
566 fDrawBuffer->reset();
567 } else {
568 flushDrawBuffer();
569 }
570
571 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000572 fGpu->forceRenderTargetFlush();
573 }
574}
575
576void GrContext::flushText() {
577 if (kText_DrawCategory == fLastDrawCategory) {
578 flushDrawBuffer();
579 }
580}
581
582void GrContext::flushDrawBuffer() {
583#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
584 fDrawBuffer->playback(fGpu);
585 fDrawBuffer->reset();
586#endif
587}
588
589bool GrContext::readPixels(int left, int top, int width, int height,
590 GrTexture::PixelConfig config, void* buffer) {
591 this->flush(true);
592 return fGpu->readPixels(left, top, width, height, config, buffer);
593}
594
595void GrContext::writePixels(int left, int top, int width, int height,
596 GrTexture::PixelConfig config, const void* buffer,
597 size_t stride) {
598
599 // TODO: when underlying api has a direct way to do this we should use it
600 // (e.g. glDrawPixels on desktop GL).
601
602 const GrGpu::TextureDesc desc = {
603 0, GrGpu::kNone_AALevel, width, height, config
604 };
605 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
606 if (NULL == texture) {
607 return;
608 }
609
610 this->flush(true);
611
612 GrAutoUnref aur(texture);
613 GrDrawTarget::AutoStateRestore asr(fGpu);
614
615 GrMatrix matrix;
616 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
617 fGpu->setViewMatrix(matrix);
618
619 fGpu->disableState(GrDrawTarget::kClip_StateBit);
620 fGpu->setAlpha(0xFF);
621 fGpu->setBlendFunc(kOne_BlendCoeff,
622 kZero_BlendCoeff);
623 fGpu->setTexture(0, texture);
624
625 GrSamplerState sampler;
626 sampler.setClampNoFilter();
627 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
628 sampler.setMatrix(matrix);
629 fGpu->setSamplerState(0, sampler);
630
631 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
632 static const int VCOUNT = 4;
633
634 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
635 if (!geo.succeeded()) {
636 return;
637 }
638 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
639 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
640}
641////////////////////////////////////////////////////////////////////////////////
642
643void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
644 target->setTexture(0, paint.getTexture());
645 target->setSamplerState(0, paint.fSampler);
646 target->setColor(paint.fColor);
647
648 if (paint.fDither) {
649 target->enableState(GrDrawTarget::kDither_StateBit);
650 } else {
651 target->disableState(GrDrawTarget::kDither_StateBit);
652 }
653 if (paint.fAntiAlias) {
654 target->enableState(GrDrawTarget::kAntialias_StateBit);
655 } else {
656 target->disableState(GrDrawTarget::kAntialias_StateBit);
657 }
658 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
659}
660
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000661GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000662 DrawCategory category) {
663 if (category != fLastDrawCategory) {
664 flushDrawBuffer();
665 fLastDrawCategory = category;
666 }
667 SetPaint(paint, fGpu);
668 GrDrawTarget* target = fGpu;
669 switch (category) {
670 case kText_DrawCategory:
671#if DEFER_TEXT_RENDERING
672 target = fDrawBuffer;
673 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
674#else
675 target = fGpu;
676#endif
677 break;
678 case kUnbuffered_DrawCategory:
679 target = fGpu;
680 break;
681 case kBuffered_DrawCategory:
682 target = fDrawBuffer;
683 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
684 break;
685 }
686 return target;
687}
688
689////////////////////////////////////////////////////////////////////////////////
690
691void GrContext::resetContext() {
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000692 fGpu->markContextDirty();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000693}
694
695void GrContext::setRenderTarget(GrRenderTarget* target) {
696 flush(false);
697 fGpu->setRenderTarget(target);
698}
699
700GrRenderTarget* GrContext::getRenderTarget() {
701 return fGpu->getRenderTarget();
702}
703
704const GrRenderTarget* GrContext::getRenderTarget() const {
705 return fGpu->getRenderTarget();
706}
707
708const GrMatrix& GrContext::getMatrix() const {
709 return fGpu->getViewMatrix();
710}
711
712void GrContext::setMatrix(const GrMatrix& m) {
713 fGpu->setViewMatrix(m);
714}
715
716void GrContext::concatMatrix(const GrMatrix& m) const {
717 fGpu->preConcatViewMatrix(m);
718}
719
720static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
721 intptr_t mask = 1 << shift;
722 if (pred) {
723 bits |= mask;
724 } else {
725 bits &= ~mask;
726 }
727 return bits;
728}
729
730void GrContext::resetStats() {
731 fGpu->resetStats();
732}
733
734const GrGpu::Stats& GrContext::getStats() const {
735 return fGpu->getStats();
736}
737
738void GrContext::printStats() const {
739 fGpu->printStats();
740}
741
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000742GrContext::GrContext(GrGpu* gpu) :
743 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
744 gpu->supportsStencilWrapOps()) {
745
bsalomon@google.com27847de2011-02-22 20:59:41 +0000746 fGpu = gpu;
747 fGpu->ref();
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000748
749 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
750 fGpu->setClipPathRenderer(fCustomPathRenderer);
751
bsalomon@google.com27847de2011-02-22 20:59:41 +0000752 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
753 MAX_TEXTURE_CACHE_BYTES);
754 fFontCache = new GrFontCache(fGpu);
755
756 fLastDrawCategory = kUnbuffered_DrawCategory;
757
758#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000759 fDrawBufferVBAllocPool =
bsalomon@google.com27847de2011-02-22 20:59:41 +0000760 new GrVertexBufferAllocPool(gpu, false,
761 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
762 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000763 fDrawBufferIBAllocPool =
bsalomon@google.com27847de2011-02-22 20:59:41 +0000764 new GrIndexBufferAllocPool(gpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000765 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000766 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
767
768 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
769 fDrawBufferIBAllocPool);
770#else
771 fDrawBuffer = NULL;
772 fDrawBufferVBAllocPool = NULL;
773 fDrawBufferIBAllocPool = NULL;
774#endif
775
776#if BATCH_RECT_TO_RECT
777 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
778#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +0000779}
780
781bool GrContext::finalizeTextureKey(GrTextureKey* key,
782 const GrSamplerState& sampler) const {
783 uint32_t bits = 0;
784 uint16_t width = key->width();
785 uint16_t height = key->height();
786
787
788 if (!fGpu->npotTextureTileSupport()) {
789 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
790
791 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
792 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
793
794 if (tiled && !isPow2) {
795 bits |= 1;
796 bits |= sampler.isFilter() ? 2 : 0;
797 }
798 }
799 key->finalize(bits);
800 return 0 != bits;
801}
802
803GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
804 GrDrawTarget* target;
805#if DEFER_TEXT_RENDERING
806 target = prepareToDraw(paint, kText_DrawCategory);
807#else
808 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
809#endif
810 SetPaint(paint, target);
811 return target;
812}
813
814const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
815 return fGpu->getQuadIndexBuffer();
816}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000817
818GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
819 GrPathIter* path,
820 GrPathFill fill) {
821 if (NULL != fCustomPathRenderer &&
822 fCustomPathRenderer->canDrawPath(target, path, fill)) {
823 return fCustomPathRenderer;
824 } else {
825 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
826 return &fDefaultPathRenderer;
827 }
828}