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