blob: b17a238c86adea4ba28aa2616d21331786c0fff8 [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);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000209 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000210 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,
bsalomon@google.comf954d8d2011-04-06 17:50:02 +0000273 bool isMultisampled,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000274 int width, int height) {
275 return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits,
bsalomon@google.comf954d8d2011-04-06 17:50:02 +0000276 isMultisampled,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000277 width, height);
278}
279
280bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
281 int width, int height) {
282 if (!fGpu->supports8BitPalette()) {
283 return false;
284 }
285
286
287 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
288
289 if (!isPow2) {
290 if (!fGpu->npotTextureSupport()) {
291 return false;
292 }
293
294 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
295 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
296 if (tiled && !fGpu->npotTextureTileSupport()) {
297 return false;
298 }
299 }
300 return true;
301}
302
303////////////////////////////////////////////////////////////////////////////////
304
305void GrContext::setClip(const GrClip& clip) {
306 fGpu->setClip(clip);
307 fGpu->enableState(GrDrawTarget::kClip_StateBit);
308}
309
310void GrContext::setClip(const GrIRect& rect) {
311 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000312 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000313 fGpu->setClip(clip);
314}
315
316////////////////////////////////////////////////////////////////////////////////
317
318void GrContext::eraseColor(GrColor color) {
319 fGpu->eraseColor(color);
320}
321
322void GrContext::drawPaint(const GrPaint& paint) {
323 // set rect to be big enough to fill the space, but not super-huge, so we
324 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000325 GrRect r;
326 r.setLTRB(0, 0,
327 GrIntToScalar(getRenderTarget()->width()),
328 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000329 GrMatrix inverse;
330 if (fGpu->getViewInverse(&inverse)) {
331 inverse.mapRect(&r);
332 } else {
333 GrPrintf("---- fGpu->getViewInverse failed\n");
334 }
335 this->drawRect(paint, r);
336}
337
338/* create a triangle strip that strokes the specified triangle. There are 8
339 unique vertices, but we repreat the last 2 to close up. Alternatively we
340 could use an indices array, and then only send 8 verts, but not sure that
341 would be faster.
342 */
343static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
344 GrScalar width) {
345 const GrScalar rad = GrScalarHalf(width);
346
347 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
348 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
349 verts[2].set(rect.fRight - rad, rect.fTop + rad);
350 verts[3].set(rect.fRight + rad, rect.fTop - rad);
351 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
352 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
353 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
354 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
355 verts[8] = verts[0];
356 verts[9] = verts[1];
357}
358
359void GrContext::drawRect(const GrPaint& paint,
360 const GrRect& rect,
361 GrScalar width,
362 const GrMatrix* matrix) {
363
364 bool textured = NULL != paint.getTexture();
365
366 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
367
368 if (width >= 0) {
369 // TODO: consider making static vertex buffers for these cases.
370 // Hairline could be done by just adding closing vertex to
371 // unitSquareVertexBuffer()
372 GrVertexLayout layout = (textured) ?
373 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
374 0;
375 static const int worstCaseVertCount = 10;
376 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
377
378 if (!geo.succeeded()) {
379 return;
380 }
381
382 GrPrimitiveType primType;
383 int vertCount;
384 GrPoint* vertex = geo.positions();
385
386 if (width > 0) {
387 vertCount = 10;
388 primType = kTriangleStrip_PrimitiveType;
389 setStrokeRectStrip(vertex, rect, width);
390 } else {
391 // hairline
392 vertCount = 5;
393 primType = kLineStrip_PrimitiveType;
394 vertex[0].set(rect.fLeft, rect.fTop);
395 vertex[1].set(rect.fRight, rect.fTop);
396 vertex[2].set(rect.fRight, rect.fBottom);
397 vertex[3].set(rect.fLeft, rect.fBottom);
398 vertex[4].set(rect.fLeft, rect.fTop);
399 }
400
401 GrDrawTarget::AutoViewMatrixRestore avmr;
402 if (NULL != matrix) {
403 avmr.set(target);
404 target->preConcatViewMatrix(*matrix);
405 target->preConcatSamplerMatrix(0, *matrix);
406 }
407
408 target->drawNonIndexed(primType, 0, vertCount);
409 } else {
410 #if GR_STATIC_RECT_VB
411 GrVertexLayout layout = (textured) ?
412 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
413 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000414 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415 fGpu->getUnitSquareVertexBuffer());
416 GrDrawTarget::AutoViewMatrixRestore avmr(target);
417 GrMatrix m;
418 m.setAll(rect.width(), 0, rect.fLeft,
419 0, rect.height(), rect.fTop,
420 0, 0, GrMatrix::I()[8]);
421
422 if (NULL != matrix) {
423 m.postConcat(*matrix);
424 }
425
426 target->preConcatViewMatrix(m);
427
428 if (textured) {
429 target->preConcatSamplerMatrix(0, m);
430 }
431 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
432 #else
433 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
434 #endif
435 }
436}
437
438void GrContext::drawRectToRect(const GrPaint& paint,
439 const GrRect& dstRect,
440 const GrRect& srcRect,
441 const GrMatrix* dstMatrix,
442 const GrMatrix* srcMatrix) {
443
444 if (NULL == paint.getTexture()) {
445 drawRect(paint, dstRect, -1, dstMatrix);
446 return;
447 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000448
bsalomon@google.com27847de2011-02-22 20:59:41 +0000449 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
450
451#if GR_STATIC_RECT_VB
452 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
453
454 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
455 GrDrawTarget::AutoViewMatrixRestore avmr(target);
456
457 GrMatrix m;
458
459 m.setAll(dstRect.width(), 0, dstRect.fLeft,
460 0, dstRect.height(), dstRect.fTop,
461 0, 0, GrMatrix::I()[8]);
462 if (NULL != dstMatrix) {
463 m.postConcat(*dstMatrix);
464 }
465 target->preConcatViewMatrix(m);
466
467 m.setAll(srcRect.width(), 0, srcRect.fLeft,
468 0, srcRect.height(), srcRect.fTop,
469 0, 0, GrMatrix::I()[8]);
470 if (NULL != srcMatrix) {
471 m.postConcat(*srcMatrix);
472 }
473 target->preConcatSamplerMatrix(0, m);
474
475 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
476 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
477#else
478
479 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000480#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +0000481 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000482#else
bsalomon@google.com27847de2011-02-22 20:59:41 +0000483 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
484#endif
485
486 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
487 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
488 srcRects[0] = &srcRect;
489 srcMatrices[0] = srcMatrix;
490
491 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
492#endif
493}
494
495void GrContext::drawVertices(const GrPaint& paint,
496 GrPrimitiveType primitiveType,
497 int vertexCount,
498 const GrPoint positions[],
499 const GrPoint texCoords[],
500 const GrColor colors[],
501 const uint16_t indices[],
502 int indexCount) {
503 GrVertexLayout layout = 0;
504 int vertexSize = sizeof(GrPoint);
505
506 GrDrawTarget::AutoReleaseGeometry geo;
507
508 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
509
510 if (NULL != paint.getTexture()) {
511 if (NULL == texCoords) {
512 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
513 } else {
514 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
515 vertexSize += sizeof(GrPoint);
516 }
517 }
518
519 if (NULL != colors) {
520 layout |= GrDrawTarget::kColor_VertexLayoutBit;
521 vertexSize += sizeof(GrColor);
522 }
523
524 if (sizeof(GrPoint) != vertexSize) {
525 if (!geo.set(target, layout, vertexCount, 0)) {
526 GrPrintf("Failed to get space for vertices!");
527 return;
528 }
529 int texOffsets[GrDrawTarget::kMaxTexCoords];
530 int colorOffset;
531 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
532 texOffsets,
533 &colorOffset);
534 void* curVertex = geo.vertices();
535
536 for (int i = 0; i < vertexCount; ++i) {
537 *((GrPoint*)curVertex) = positions[i];
538
539 if (texOffsets[0] > 0) {
540 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
541 }
542 if (colorOffset > 0) {
543 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
544 }
545 curVertex = (void*)((intptr_t)curVertex + vsize);
546 }
547 } else {
548 target->setVertexSourceToArray(layout, positions, vertexCount);
549 }
550
551 if (NULL != indices) {
552 target->setIndexSourceToArray(indices, indexCount);
553 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
554 } else {
555 target->drawNonIndexed(primitiveType, 0, vertexCount);
556 }
557}
558
559
560////////////////////////////////////////////////////////////////////////////////
561
562void GrContext::drawPath(const GrPaint& paint,
563 GrPathIter* path,
564 GrPathFill fill,
565 const GrPoint* translate) {
566
567
568 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
569
570 GrDrawTarget::StageBitfield enabledStages = 0;
571 if (NULL != paint.getTexture()) {
572 enabledStages |= 1;
573 }
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000574 GrPathRenderer* pr = getPathRenderer(target, path, fill);
575 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000576}
577
bsalomon@google.comd302f142011-03-03 13:54:13 +0000578void GrContext::drawPath(const GrPaint& paint,
579 const GrPath& path,
580 GrPathFill fill,
581 const GrPoint* translate) {
582 GrPath::Iter iter(path);
583 this->drawPath(paint, &iter, fill, translate);
584}
585
586
bsalomon@google.com27847de2011-02-22 20:59:41 +0000587////////////////////////////////////////////////////////////////////////////////
588
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000589void GrContext::flush(int flagsBitfield) {
590 if (kDiscard_FlushBit & flagsBitfield) {
591 fDrawBuffer->reset();
592 } else {
593 flushDrawBuffer();
594 }
595
596 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000597 fGpu->forceRenderTargetFlush();
598 }
599}
600
601void GrContext::flushText() {
602 if (kText_DrawCategory == fLastDrawCategory) {
603 flushDrawBuffer();
604 }
605}
606
607void GrContext::flushDrawBuffer() {
608#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
609 fDrawBuffer->playback(fGpu);
610 fDrawBuffer->reset();
611#endif
612}
613
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000614bool GrContext::readTexturePixels(GrTexture* texture,
615 int left, int top, int width, int height,
616 GrPixelConfig config, void* buffer) {
617
618 // TODO: code read pixels for textures that aren't rendertargets
619
620 this->flush();
621 GrRenderTarget* target = texture->asRenderTarget();
622 if (NULL != target) {
623 return fGpu->readPixels(target,
624 left, top, width, height,
625 config, buffer);
626 } else {
627 return false;
628 }
629}
630
631bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
632 int left, int top, int width, int height,
633 GrPixelConfig config, void* buffer) {
634 uint32_t flushFlags = 0;
635 if (NULL == target) {
636 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
637 }
638
639 this->flush(flushFlags);
640 return fGpu->readPixels(target,
641 left, top, width, height,
642 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000643}
644
645void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000646 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000647 size_t stride) {
648
649 // TODO: when underlying api has a direct way to do this we should use it
650 // (e.g. glDrawPixels on desktop GL).
651
652 const GrGpu::TextureDesc desc = {
653 0, GrGpu::kNone_AALevel, width, height, config
654 };
655 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
656 if (NULL == texture) {
657 return;
658 }
659
660 this->flush(true);
661
662 GrAutoUnref aur(texture);
663 GrDrawTarget::AutoStateRestore asr(fGpu);
664
665 GrMatrix matrix;
666 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
667 fGpu->setViewMatrix(matrix);
668
669 fGpu->disableState(GrDrawTarget::kClip_StateBit);
670 fGpu->setAlpha(0xFF);
671 fGpu->setBlendFunc(kOne_BlendCoeff,
672 kZero_BlendCoeff);
673 fGpu->setTexture(0, texture);
674
675 GrSamplerState sampler;
676 sampler.setClampNoFilter();
677 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
678 sampler.setMatrix(matrix);
679 fGpu->setSamplerState(0, sampler);
680
681 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
682 static const int VCOUNT = 4;
683
684 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
685 if (!geo.succeeded()) {
686 return;
687 }
688 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
689 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
690}
691////////////////////////////////////////////////////////////////////////////////
692
693void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
694 target->setTexture(0, paint.getTexture());
695 target->setSamplerState(0, paint.fSampler);
696 target->setColor(paint.fColor);
697
698 if (paint.fDither) {
699 target->enableState(GrDrawTarget::kDither_StateBit);
700 } else {
701 target->disableState(GrDrawTarget::kDither_StateBit);
702 }
703 if (paint.fAntiAlias) {
704 target->enableState(GrDrawTarget::kAntialias_StateBit);
705 } else {
706 target->disableState(GrDrawTarget::kAntialias_StateBit);
707 }
708 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
709}
710
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000711GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000712 DrawCategory category) {
713 if (category != fLastDrawCategory) {
714 flushDrawBuffer();
715 fLastDrawCategory = category;
716 }
717 SetPaint(paint, fGpu);
718 GrDrawTarget* target = fGpu;
719 switch (category) {
720 case kText_DrawCategory:
721#if DEFER_TEXT_RENDERING
722 target = fDrawBuffer;
723 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
724#else
725 target = fGpu;
726#endif
727 break;
728 case kUnbuffered_DrawCategory:
729 target = fGpu;
730 break;
731 case kBuffered_DrawCategory:
732 target = fDrawBuffer;
733 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
734 break;
735 }
736 return target;
737}
738
739////////////////////////////////////////////////////////////////////////////////
740
bsalomon@google.com27847de2011-02-22 20:59:41 +0000741void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000742 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000743 fGpu->setRenderTarget(target);
744}
745
746GrRenderTarget* GrContext::getRenderTarget() {
747 return fGpu->getRenderTarget();
748}
749
750const GrRenderTarget* GrContext::getRenderTarget() const {
751 return fGpu->getRenderTarget();
752}
753
754const GrMatrix& GrContext::getMatrix() const {
755 return fGpu->getViewMatrix();
756}
757
758void GrContext::setMatrix(const GrMatrix& m) {
759 fGpu->setViewMatrix(m);
760}
761
762void GrContext::concatMatrix(const GrMatrix& m) const {
763 fGpu->preConcatViewMatrix(m);
764}
765
766static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
767 intptr_t mask = 1 << shift;
768 if (pred) {
769 bits |= mask;
770 } else {
771 bits &= ~mask;
772 }
773 return bits;
774}
775
776void GrContext::resetStats() {
777 fGpu->resetStats();
778}
779
780const GrGpu::Stats& GrContext::getStats() const {
781 return fGpu->getStats();
782}
783
784void GrContext::printStats() const {
785 fGpu->printStats();
786}
787
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000788GrContext::GrContext(GrGpu* gpu) :
789 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
790 gpu->supportsStencilWrapOps()) {
791
bsalomon@google.com27847de2011-02-22 20:59:41 +0000792 fGpu = gpu;
793 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000794 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000795
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000796 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
797 fGpu->setClipPathRenderer(fCustomPathRenderer);
798
bsalomon@google.com27847de2011-02-22 20:59:41 +0000799 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
800 MAX_TEXTURE_CACHE_BYTES);
801 fFontCache = new GrFontCache(fGpu);
802
803 fLastDrawCategory = kUnbuffered_DrawCategory;
804
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000805 fDrawBuffer = NULL;
806 fDrawBufferVBAllocPool = NULL;
807 fDrawBufferIBAllocPool = NULL;
808
809 this->setupDrawBuffer();
810}
811
812void GrContext::setupDrawBuffer() {
813
814 GrAssert(NULL == fDrawBuffer);
815 GrAssert(NULL == fDrawBufferVBAllocPool);
816 GrAssert(NULL == fDrawBufferIBAllocPool);
817
bsalomon@google.com27847de2011-02-22 20:59:41 +0000818#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000819 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000820 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000821 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
822 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000823 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000824 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000825 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000826 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
827
828 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
829 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000830#endif
831
832#if BATCH_RECT_TO_RECT
833 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
834#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +0000835}
836
837bool GrContext::finalizeTextureKey(GrTextureKey* key,
838 const GrSamplerState& sampler) const {
839 uint32_t bits = 0;
840 uint16_t width = key->width();
841 uint16_t height = key->height();
842
843
844 if (!fGpu->npotTextureTileSupport()) {
845 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
846
847 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
848 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
849
850 if (tiled && !isPow2) {
851 bits |= 1;
852 bits |= sampler.isFilter() ? 2 : 0;
853 }
854 }
855 key->finalize(bits);
856 return 0 != bits;
857}
858
859GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
860 GrDrawTarget* target;
861#if DEFER_TEXT_RENDERING
862 target = prepareToDraw(paint, kText_DrawCategory);
863#else
864 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
865#endif
866 SetPaint(paint, target);
867 return target;
868}
869
870const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
871 return fGpu->getQuadIndexBuffer();
872}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000873
874GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
875 GrPathIter* path,
876 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000877 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000878 fCustomPathRenderer->canDrawPath(target, path, fill)) {
879 return fCustomPathRenderer;
880 } else {
881 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
882 return &fDefaultPathRenderer;
883 }
884}