blob: a047895cedddd3992be7cc6af203bc9e81dee7b6 [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;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000065 delete fDrawBufferIBAllocPool;
bsalomon@google.com27847de2011-02-22 20:59:41 +000066 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());
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 }
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;
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 }
549 fPathRenderer->drawPath(target, enabledStages, path, fill, translate);
550}
551
bsalomon@google.comd302f142011-03-03 13:54:13 +0000552void GrContext::drawPath(const GrPaint& paint,
553 const GrPath& path,
554 GrPathFill fill,
555 const GrPoint* translate) {
556 GrPath::Iter iter(path);
557 this->drawPath(paint, &iter, fill, translate);
558}
559
560
bsalomon@google.com27847de2011-02-22 20:59:41 +0000561////////////////////////////////////////////////////////////////////////////////
562
563void GrContext::flush(bool flushRenderTarget) {
564 flushDrawBuffer();
565 if (flushRenderTarget) {
566 fGpu->forceRenderTargetFlush();
567 }
568}
569
570void GrContext::flushText() {
571 if (kText_DrawCategory == fLastDrawCategory) {
572 flushDrawBuffer();
573 }
574}
575
576void GrContext::flushDrawBuffer() {
577#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
578 fDrawBuffer->playback(fGpu);
579 fDrawBuffer->reset();
580#endif
581}
582
583bool GrContext::readPixels(int left, int top, int width, int height,
584 GrTexture::PixelConfig config, void* buffer) {
585 this->flush(true);
586 return fGpu->readPixels(left, top, width, height, config, buffer);
587}
588
589void GrContext::writePixels(int left, int top, int width, int height,
590 GrTexture::PixelConfig config, const void* buffer,
591 size_t stride) {
592
593 // TODO: when underlying api has a direct way to do this we should use it
594 // (e.g. glDrawPixels on desktop GL).
595
596 const GrGpu::TextureDesc desc = {
597 0, GrGpu::kNone_AALevel, width, height, config
598 };
599 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
600 if (NULL == texture) {
601 return;
602 }
603
604 this->flush(true);
605
606 GrAutoUnref aur(texture);
607 GrDrawTarget::AutoStateRestore asr(fGpu);
608
609 GrMatrix matrix;
610 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
611 fGpu->setViewMatrix(matrix);
612
613 fGpu->disableState(GrDrawTarget::kClip_StateBit);
614 fGpu->setAlpha(0xFF);
615 fGpu->setBlendFunc(kOne_BlendCoeff,
616 kZero_BlendCoeff);
617 fGpu->setTexture(0, texture);
618
619 GrSamplerState sampler;
620 sampler.setClampNoFilter();
621 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
622 sampler.setMatrix(matrix);
623 fGpu->setSamplerState(0, sampler);
624
625 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
626 static const int VCOUNT = 4;
627
628 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
629 if (!geo.succeeded()) {
630 return;
631 }
632 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
633 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
634}
635////////////////////////////////////////////////////////////////////////////////
636
637void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
638 target->setTexture(0, paint.getTexture());
639 target->setSamplerState(0, paint.fSampler);
640 target->setColor(paint.fColor);
641
642 if (paint.fDither) {
643 target->enableState(GrDrawTarget::kDither_StateBit);
644 } else {
645 target->disableState(GrDrawTarget::kDither_StateBit);
646 }
647 if (paint.fAntiAlias) {
648 target->enableState(GrDrawTarget::kAntialias_StateBit);
649 } else {
650 target->disableState(GrDrawTarget::kAntialias_StateBit);
651 }
652 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
653}
654
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000655GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656 DrawCategory category) {
657 if (category != fLastDrawCategory) {
658 flushDrawBuffer();
659 fLastDrawCategory = category;
660 }
661 SetPaint(paint, fGpu);
662 GrDrawTarget* target = fGpu;
663 switch (category) {
664 case kText_DrawCategory:
665#if DEFER_TEXT_RENDERING
666 target = fDrawBuffer;
667 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
668#else
669 target = fGpu;
670#endif
671 break;
672 case kUnbuffered_DrawCategory:
673 target = fGpu;
674 break;
675 case kBuffered_DrawCategory:
676 target = fDrawBuffer;
677 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
678 break;
679 }
680 return target;
681}
682
683////////////////////////////////////////////////////////////////////////////////
684
685void GrContext::resetContext() {
686 fGpu->resetContext();
687}
688
689void GrContext::setRenderTarget(GrRenderTarget* target) {
690 flush(false);
691 fGpu->setRenderTarget(target);
692}
693
694GrRenderTarget* GrContext::getRenderTarget() {
695 return fGpu->getRenderTarget();
696}
697
698const GrRenderTarget* GrContext::getRenderTarget() const {
699 return fGpu->getRenderTarget();
700}
701
702const GrMatrix& GrContext::getMatrix() const {
703 return fGpu->getViewMatrix();
704}
705
706void GrContext::setMatrix(const GrMatrix& m) {
707 fGpu->setViewMatrix(m);
708}
709
710void GrContext::concatMatrix(const GrMatrix& m) const {
711 fGpu->preConcatViewMatrix(m);
712}
713
714static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
715 intptr_t mask = 1 << shift;
716 if (pred) {
717 bits |= mask;
718 } else {
719 bits &= ~mask;
720 }
721 return bits;
722}
723
724void GrContext::resetStats() {
725 fGpu->resetStats();
726}
727
728const GrGpu::Stats& GrContext::getStats() const {
729 return fGpu->getStats();
730}
731
732void GrContext::printStats() const {
733 fGpu->printStats();
734}
735
736GrContext::GrContext(GrGpu* gpu) {
737 fGpu = gpu;
738 fGpu->ref();
739 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
740 MAX_TEXTURE_CACHE_BYTES);
741 fFontCache = new GrFontCache(fGpu);
742
743 fLastDrawCategory = kUnbuffered_DrawCategory;
744
745#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000746 fDrawBufferVBAllocPool =
bsalomon@google.com27847de2011-02-22 20:59:41 +0000747 new GrVertexBufferAllocPool(gpu, false,
748 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
749 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000750 fDrawBufferIBAllocPool =
bsalomon@google.com27847de2011-02-22 20:59:41 +0000751 new GrIndexBufferAllocPool(gpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000752 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000753 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
754
755 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
756 fDrawBufferIBAllocPool);
757#else
758 fDrawBuffer = NULL;
759 fDrawBufferVBAllocPool = NULL;
760 fDrawBufferIBAllocPool = NULL;
761#endif
762
763#if BATCH_RECT_TO_RECT
764 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
765#endif
bsalomon@google.comd302f142011-03-03 13:54:13 +0000766 fPathRenderer = new GrDefaultPathRenderer(fGpu->supportsTwoSidedStencil(),
767 fGpu->supportsStencilWrapOps());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000768}
769
770bool GrContext::finalizeTextureKey(GrTextureKey* key,
771 const GrSamplerState& sampler) const {
772 uint32_t bits = 0;
773 uint16_t width = key->width();
774 uint16_t height = key->height();
775
776
777 if (!fGpu->npotTextureTileSupport()) {
778 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
779
780 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
781 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
782
783 if (tiled && !isPow2) {
784 bits |= 1;
785 bits |= sampler.isFilter() ? 2 : 0;
786 }
787 }
788 key->finalize(bits);
789 return 0 != bits;
790}
791
792GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
793 GrDrawTarget* target;
794#if DEFER_TEXT_RENDERING
795 target = prepareToDraw(paint, kText_DrawCategory);
796#else
797 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
798#endif
799 SetPaint(paint, target);
800 return target;
801}
802
803const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
804 return fGpu->getQuadIndexBuffer();
805}