blob: a0f5c51f9b480f10a67dd0bf0b5b53ede969a3b0 [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,
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
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000612bool GrContext::readTexturePixels(GrTexture* texture,
613 int left, int top, int width, int height,
614 GrPixelConfig config, void* buffer) {
615
616 // TODO: code read pixels for textures that aren't rendertargets
617
618 this->flush();
619 GrRenderTarget* target = texture->asRenderTarget();
620 if (NULL != target) {
621 return fGpu->readPixels(target,
622 left, top, width, height,
623 config, buffer);
624 } else {
625 return false;
626 }
627}
628
629bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
630 int left, int top, int width, int height,
631 GrPixelConfig config, void* buffer) {
632 uint32_t flushFlags = 0;
633 if (NULL == target) {
634 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
635 }
636
637 this->flush(flushFlags);
638 return fGpu->readPixels(target,
639 left, top, width, height,
640 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000641}
642
643void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000644 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000645 size_t stride) {
646
647 // TODO: when underlying api has a direct way to do this we should use it
648 // (e.g. glDrawPixels on desktop GL).
649
650 const GrGpu::TextureDesc desc = {
651 0, GrGpu::kNone_AALevel, width, height, config
652 };
653 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
654 if (NULL == texture) {
655 return;
656 }
657
658 this->flush(true);
659
660 GrAutoUnref aur(texture);
661 GrDrawTarget::AutoStateRestore asr(fGpu);
662
663 GrMatrix matrix;
664 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
665 fGpu->setViewMatrix(matrix);
666
667 fGpu->disableState(GrDrawTarget::kClip_StateBit);
668 fGpu->setAlpha(0xFF);
669 fGpu->setBlendFunc(kOne_BlendCoeff,
670 kZero_BlendCoeff);
671 fGpu->setTexture(0, texture);
672
673 GrSamplerState sampler;
674 sampler.setClampNoFilter();
675 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
676 sampler.setMatrix(matrix);
677 fGpu->setSamplerState(0, sampler);
678
679 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
680 static const int VCOUNT = 4;
681
682 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
683 if (!geo.succeeded()) {
684 return;
685 }
686 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
687 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
688}
689////////////////////////////////////////////////////////////////////////////////
690
691void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
692 target->setTexture(0, paint.getTexture());
693 target->setSamplerState(0, paint.fSampler);
694 target->setColor(paint.fColor);
695
696 if (paint.fDither) {
697 target->enableState(GrDrawTarget::kDither_StateBit);
698 } else {
699 target->disableState(GrDrawTarget::kDither_StateBit);
700 }
701 if (paint.fAntiAlias) {
702 target->enableState(GrDrawTarget::kAntialias_StateBit);
703 } else {
704 target->disableState(GrDrawTarget::kAntialias_StateBit);
705 }
706 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
707}
708
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000709GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000710 DrawCategory category) {
711 if (category != fLastDrawCategory) {
712 flushDrawBuffer();
713 fLastDrawCategory = category;
714 }
715 SetPaint(paint, fGpu);
716 GrDrawTarget* target = fGpu;
717 switch (category) {
718 case kText_DrawCategory:
719#if DEFER_TEXT_RENDERING
720 target = fDrawBuffer;
721 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
722#else
723 target = fGpu;
724#endif
725 break;
726 case kUnbuffered_DrawCategory:
727 target = fGpu;
728 break;
729 case kBuffered_DrawCategory:
730 target = fDrawBuffer;
731 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
732 break;
733 }
734 return target;
735}
736
737////////////////////////////////////////////////////////////////////////////////
738
bsalomon@google.com27847de2011-02-22 20:59:41 +0000739void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000740 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000741 fGpu->setRenderTarget(target);
742}
743
744GrRenderTarget* GrContext::getRenderTarget() {
745 return fGpu->getRenderTarget();
746}
747
748const GrRenderTarget* GrContext::getRenderTarget() const {
749 return fGpu->getRenderTarget();
750}
751
752const GrMatrix& GrContext::getMatrix() const {
753 return fGpu->getViewMatrix();
754}
755
756void GrContext::setMatrix(const GrMatrix& m) {
757 fGpu->setViewMatrix(m);
758}
759
760void GrContext::concatMatrix(const GrMatrix& m) const {
761 fGpu->preConcatViewMatrix(m);
762}
763
764static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
765 intptr_t mask = 1 << shift;
766 if (pred) {
767 bits |= mask;
768 } else {
769 bits &= ~mask;
770 }
771 return bits;
772}
773
774void GrContext::resetStats() {
775 fGpu->resetStats();
776}
777
778const GrGpu::Stats& GrContext::getStats() const {
779 return fGpu->getStats();
780}
781
782void GrContext::printStats() const {
783 fGpu->printStats();
784}
785
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000786GrContext::GrContext(GrGpu* gpu) :
787 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
788 gpu->supportsStencilWrapOps()) {
789
bsalomon@google.com27847de2011-02-22 20:59:41 +0000790 fGpu = gpu;
791 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000792 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000793
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000794 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
795 fGpu->setClipPathRenderer(fCustomPathRenderer);
796
bsalomon@google.com27847de2011-02-22 20:59:41 +0000797 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
798 MAX_TEXTURE_CACHE_BYTES);
799 fFontCache = new GrFontCache(fGpu);
800
801 fLastDrawCategory = kUnbuffered_DrawCategory;
802
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000803 fDrawBuffer = NULL;
804 fDrawBufferVBAllocPool = NULL;
805 fDrawBufferIBAllocPool = NULL;
806
807 this->setupDrawBuffer();
808}
809
810void GrContext::setupDrawBuffer() {
811
812 GrAssert(NULL == fDrawBuffer);
813 GrAssert(NULL == fDrawBufferVBAllocPool);
814 GrAssert(NULL == fDrawBufferIBAllocPool);
815
bsalomon@google.com27847de2011-02-22 20:59:41 +0000816#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000817 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000818 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000819 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
820 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000821 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000822 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000823 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000824 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
825
826 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
827 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000828#endif
829
830#if BATCH_RECT_TO_RECT
831 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
832#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +0000833}
834
835bool GrContext::finalizeTextureKey(GrTextureKey* key,
836 const GrSamplerState& sampler) const {
837 uint32_t bits = 0;
838 uint16_t width = key->width();
839 uint16_t height = key->height();
840
841
842 if (!fGpu->npotTextureTileSupport()) {
843 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
844
845 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
846 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
847
848 if (tiled && !isPow2) {
849 bits |= 1;
850 bits |= sampler.isFilter() ? 2 : 0;
851 }
852 }
853 key->finalize(bits);
854 return 0 != bits;
855}
856
857GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
858 GrDrawTarget* target;
859#if DEFER_TEXT_RENDERING
860 target = prepareToDraw(paint, kText_DrawCategory);
861#else
862 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
863#endif
864 SetPaint(paint, target);
865 return target;
866}
867
868const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
869 return fGpu->getQuadIndexBuffer();
870}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000871
872GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
873 GrPathIter* path,
874 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000875 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000876 fCustomPathRenderer->canDrawPath(target, path, fill)) {
877 return fCustomPathRenderer;
878 } else {
879 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
880 return &fDefaultPathRenderer;
881 }
882}