blob: d14f3743e6ab2e8921f7741a73217bcb41a9d4e2 [file] [log] [blame]
bsalomon@google.com27847de2011-02-22 20:59:41 +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
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;
65 delete fDrawBufferVBAllocPool;
66 delete fPathRenderer;
67}
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 |
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) {
145 GrDrawTarget::AutoStateRestore asr(fGpu);
146 fGpu->setRenderTarget(texture->asRenderTarget());
147 fGpu->setTexture(0, clampEntry->texture());
148 fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass);
149 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 }
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
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;
287 clip.setRect(rect);
288 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
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 }
307 this->drawRect(paint, r);
308}
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
331void GrContext::drawRect(const GrPaint& paint,
332 const GrRect& rect,
333 GrScalar width,
334 const GrMatrix* matrix) {
335
336 bool textured = NULL != paint.getTexture();
337
338 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
339
340 if (width >= 0) {
341 // TODO: consider making static vertex buffers for these cases.
342 // Hairline could be done by just adding closing vertex to
343 // unitSquareVertexBuffer()
344 GrVertexLayout layout = (textured) ?
345 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
346 0;
347 static const int worstCaseVertCount = 10;
348 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
349
350 if (!geo.succeeded()) {
351 return;
352 }
353
354 GrPrimitiveType primType;
355 int vertCount;
356 GrPoint* vertex = geo.positions();
357
358 if (width > 0) {
359 vertCount = 10;
360 primType = kTriangleStrip_PrimitiveType;
361 setStrokeRectStrip(vertex, rect, width);
362 } else {
363 // hairline
364 vertCount = 5;
365 primType = kLineStrip_PrimitiveType;
366 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 }
372
373 GrDrawTarget::AutoViewMatrixRestore avmr;
374 if (NULL != matrix) {
375 avmr.set(target);
376 target->preConcatViewMatrix(*matrix);
377 target->preConcatSamplerMatrix(0, *matrix);
378 }
379
380 target->drawNonIndexed(primType, 0, vertCount);
381 } else {
382 #if GR_STATIC_RECT_VB
383 GrVertexLayout layout = (textured) ?
384 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
385 0;
386 target->setVertexSourceToBuffer(layout,
387 fGpu->getUnitSquareVertexBuffer());
388 GrDrawTarget::AutoViewMatrixRestore avmr(target);
389 GrMatrix m;
390 m.setAll(rect.width(), 0, rect.fLeft,
391 0, rect.height(), rect.fTop,
392 0, 0, GrMatrix::I()[8]);
393
394 if (NULL != matrix) {
395 m.postConcat(*matrix);
396 }
397
398 target->preConcatViewMatrix(m);
399
400 if (textured) {
401 target->preConcatSamplerMatrix(0, m);
402 }
403 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
404 #else
405 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
406 #endif
407 }
408}
409
410void GrContext::drawRectToRect(const GrPaint& paint,
411 const GrRect& dstRect,
412 const GrRect& srcRect,
413 const GrMatrix* dstMatrix,
414 const GrMatrix* srcMatrix) {
415
416 if (NULL == paint.getTexture()) {
417 drawRect(paint, dstRect, -1, dstMatrix);
418 return;
419 }
420
421 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
422
423#if GR_STATIC_RECT_VB
424 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
425
426 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
427 GrDrawTarget::AutoViewMatrixRestore avmr(target);
428
429 GrMatrix m;
430
431 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 }
437 target->preConcatViewMatrix(m);
438
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 }
445 target->preConcatSamplerMatrix(0, m);
446
447 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
448 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
449#else
450
451 GrDrawTarget* target;
452#if BATCH_RECT_TO_RECT
453 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
454#else
455 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
456#endif
457
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
465}
466
467void GrContext::drawVertices(const GrPaint& paint,
468 GrPrimitiveType primitiveType,
469 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;
476 int vertexSize = sizeof(GrPoint);
477
478 GrDrawTarget::AutoReleaseGeometry geo;
479
480 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
481
482 if (NULL != paint.getTexture()) {
483 if (NULL == texCoords) {
484 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
485 } else {
486 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
487 vertexSize += sizeof(GrPoint);
488 }
489 }
490
491 if (NULL != colors) {
492 layout |= GrDrawTarget::kColor_VertexLayoutBit;
493 vertexSize += sizeof(GrColor);
494 }
495
496 if (sizeof(GrPoint) != vertexSize) {
497 if (!geo.set(target, layout, vertexCount, 0)) {
498 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 {
520 target->setVertexSourceToArray(layout, positions, vertexCount);
521 }
522
523 if (NULL != indices) {
524 target->setIndexSourceToArray(indices, indexCount);
525 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
526 } else {
527 target->drawNonIndexed(primitiveType, 0, vertexCount);
528 }
529}
530
531
532////////////////////////////////////////////////////////////////////////////////
533
534void GrContext::drawPath(const GrPaint& paint,
535 GrPathIter* path,
536 GrPathFill fill,
537 const GrPoint* translate) {
538
539
540 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
541
542 GrDrawTarget::StageBitfield enabledStages = 0;
543 if (NULL != paint.getTexture()) {
544 enabledStages |= 1;
545 }
546 fPathRenderer->drawPath(target, enabledStages, path, fill, translate);
547}
548
549////////////////////////////////////////////////////////////////////////////////
550
551void GrContext::flush(bool flushRenderTarget) {
552 flushDrawBuffer();
553 if (flushRenderTarget) {
554 fGpu->forceRenderTargetFlush();
555 }
556}
557
558void GrContext::flushText() {
559 if (kText_DrawCategory == fLastDrawCategory) {
560 flushDrawBuffer();
561 }
562}
563
564void GrContext::flushDrawBuffer() {
565#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
566 fDrawBuffer->playback(fGpu);
567 fDrawBuffer->reset();
568#endif
569}
570
571bool 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) {
580
581 // TODO: when underlying api has a direct way to do this we should use it
582 // (e.g. glDrawPixels on desktop GL).
583
584 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);
600
601 fGpu->disableState(GrDrawTarget::kClip_StateBit);
602 fGpu->setAlpha(0xFF);
603 fGpu->setBlendFunc(kOne_BlendCoeff,
604 kZero_BlendCoeff);
605 fGpu->setTexture(0, texture);
606
607 GrSamplerState sampler;
608 sampler.setClampNoFilter();
609 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
610 sampler.setMatrix(matrix);
611 fGpu->setSamplerState(0, sampler);
612
613 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);
621 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
622}
623////////////////////////////////////////////////////////////////////////////////
624
625void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
626 target->setTexture(0, paint.getTexture());
627 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
643GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
644 DrawCategory category) {
645 if (category != fLastDrawCategory) {
646 flushDrawBuffer();
647 fLastDrawCategory = category;
648 }
649 SetPaint(paint, fGpu);
650 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;
669}
670
671////////////////////////////////////////////////////////////////////////////////
672
673void GrContext::resetContext() {
674 fGpu->resetContext();
675}
676
677void GrContext::setRenderTarget(GrRenderTarget* target) {
678 flush(false);
679 fGpu->setRenderTarget(target);
680}
681
682GrRenderTarget* GrContext::getRenderTarget() {
683 return fGpu->getRenderTarget();
684}
685
686const GrRenderTarget* GrContext::getRenderTarget() const {
687 return fGpu->getRenderTarget();
688}
689
690const GrMatrix& GrContext::getMatrix() const {
691 return fGpu->getViewMatrix();
692}
693
694void GrContext::setMatrix(const GrMatrix& m) {
695 fGpu->setViewMatrix(m);
696}
697
698void GrContext::concatMatrix(const GrMatrix& m) const {
699 fGpu->preConcatViewMatrix(m);
700}
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
712void 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
724GrContext::GrContext(GrGpu* gpu) {
725 fGpu = gpu;
726 fGpu->ref();
727 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
728 MAX_TEXTURE_CACHE_BYTES);
729 fFontCache = new GrFontCache(fGpu);
730
731 fLastDrawCategory = kUnbuffered_DrawCategory;
732
733#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);
745#else
746 fDrawBuffer = NULL;
747 fDrawBufferVBAllocPool = NULL;
748 fDrawBufferIBAllocPool = NULL;
749#endif
750
751#if BATCH_RECT_TO_RECT
752 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
753#endif
754 fPathRenderer = new GrDefaultPathRenderer(fGpu->supportsSingleStencilPassWinding());
755}
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();
762
763
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) {
771 bits |= 1;
772 bits |= sampler.isFilter() ? 2 : 0;
773 }
774 }
775 key->finalize(bits);
776 return 0 != bits;
777}
778
779GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
780 GrDrawTarget* target;
781#if DEFER_TEXT_RENDERING
782 target = prepareToDraw(paint, kText_DrawCategory);
783#else
784 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
785#endif
786 SetPaint(paint, target);
787 return target;
788}
789
790const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
791 return fGpu->getQuadIndexBuffer();
792}