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