blob: f68564a2ba18adcee45bb6dbbe37794cf28c31af [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
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000270GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
271 // validate flags here so that GrGpu subclasses don't have to check
272 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
273 0 != desc.fRenderTargetFlags) {
274 return NULL;
275 }
276 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
277 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
278 return NULL;
279 }
280 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
281 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
282 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
283 return NULL;
284 }
285 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000286}
287
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000288///////////////////////////////////////////////////////////////////////////////
289
bsalomon@google.com27847de2011-02-22 20:59:41 +0000290bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
291 int width, int height) {
292 if (!fGpu->supports8BitPalette()) {
293 return false;
294 }
295
296
297 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
298
299 if (!isPow2) {
300 if (!fGpu->npotTextureSupport()) {
301 return false;
302 }
303
304 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
305 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
306 if (tiled && !fGpu->npotTextureTileSupport()) {
307 return false;
308 }
309 }
310 return true;
311}
312
313////////////////////////////////////////////////////////////////////////////////
314
315void GrContext::setClip(const GrClip& clip) {
316 fGpu->setClip(clip);
317 fGpu->enableState(GrDrawTarget::kClip_StateBit);
318}
319
320void GrContext::setClip(const GrIRect& rect) {
321 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000322 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000323 fGpu->setClip(clip);
324}
325
326////////////////////////////////////////////////////////////////////////////////
327
bsalomon@google.com398109c2011-04-14 18:40:27 +0000328void GrContext::clear(GrColor color) {
329 // gpu flush call is immediate, must flush.
330 // (could in theory skip draws to current render target.)
331 this->flush();
332 fGpu->clear(color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000333}
334
335void GrContext::drawPaint(const GrPaint& paint) {
336 // set rect to be big enough to fill the space, but not super-huge, so we
337 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000338 GrRect r;
339 r.setLTRB(0, 0,
340 GrIntToScalar(getRenderTarget()->width()),
341 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000342 GrMatrix inverse;
343 if (fGpu->getViewInverse(&inverse)) {
344 inverse.mapRect(&r);
345 } else {
346 GrPrintf("---- fGpu->getViewInverse failed\n");
347 }
348 this->drawRect(paint, r);
349}
350
351/* create a triangle strip that strokes the specified triangle. There are 8
352 unique vertices, but we repreat the last 2 to close up. Alternatively we
353 could use an indices array, and then only send 8 verts, but not sure that
354 would be faster.
355 */
356static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect,
357 GrScalar width) {
358 const GrScalar rad = GrScalarHalf(width);
359
360 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
361 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
362 verts[2].set(rect.fRight - rad, rect.fTop + rad);
363 verts[3].set(rect.fRight + rad, rect.fTop - rad);
364 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
365 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
366 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
367 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
368 verts[8] = verts[0];
369 verts[9] = verts[1];
370}
371
372void GrContext::drawRect(const GrPaint& paint,
373 const GrRect& rect,
374 GrScalar width,
375 const GrMatrix* matrix) {
376
377 bool textured = NULL != paint.getTexture();
378
379 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
380
381 if (width >= 0) {
382 // TODO: consider making static vertex buffers for these cases.
383 // Hairline could be done by just adding closing vertex to
384 // unitSquareVertexBuffer()
385 GrVertexLayout layout = (textured) ?
386 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
387 0;
388 static const int worstCaseVertCount = 10;
389 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
390
391 if (!geo.succeeded()) {
392 return;
393 }
394
395 GrPrimitiveType primType;
396 int vertCount;
397 GrPoint* vertex = geo.positions();
398
399 if (width > 0) {
400 vertCount = 10;
401 primType = kTriangleStrip_PrimitiveType;
402 setStrokeRectStrip(vertex, rect, width);
403 } else {
404 // hairline
405 vertCount = 5;
406 primType = kLineStrip_PrimitiveType;
407 vertex[0].set(rect.fLeft, rect.fTop);
408 vertex[1].set(rect.fRight, rect.fTop);
409 vertex[2].set(rect.fRight, rect.fBottom);
410 vertex[3].set(rect.fLeft, rect.fBottom);
411 vertex[4].set(rect.fLeft, rect.fTop);
412 }
413
414 GrDrawTarget::AutoViewMatrixRestore avmr;
415 if (NULL != matrix) {
416 avmr.set(target);
417 target->preConcatViewMatrix(*matrix);
418 target->preConcatSamplerMatrix(0, *matrix);
419 }
420
421 target->drawNonIndexed(primType, 0, vertCount);
422 } else {
423 #if GR_STATIC_RECT_VB
424 GrVertexLayout layout = (textured) ?
425 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
426 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000427 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000428 fGpu->getUnitSquareVertexBuffer());
429 GrDrawTarget::AutoViewMatrixRestore avmr(target);
430 GrMatrix m;
431 m.setAll(rect.width(), 0, rect.fLeft,
432 0, rect.height(), rect.fTop,
433 0, 0, GrMatrix::I()[8]);
434
435 if (NULL != matrix) {
436 m.postConcat(*matrix);
437 }
438
439 target->preConcatViewMatrix(m);
440
441 if (textured) {
442 target->preConcatSamplerMatrix(0, m);
443 }
444 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
445 #else
446 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
447 #endif
448 }
449}
450
451void GrContext::drawRectToRect(const GrPaint& paint,
452 const GrRect& dstRect,
453 const GrRect& srcRect,
454 const GrMatrix* dstMatrix,
455 const GrMatrix* srcMatrix) {
456
457 if (NULL == paint.getTexture()) {
458 drawRect(paint, dstRect, -1, dstMatrix);
459 return;
460 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000461
bsalomon@google.com27847de2011-02-22 20:59:41 +0000462 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
463
464#if GR_STATIC_RECT_VB
465 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
466
467 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
468 GrDrawTarget::AutoViewMatrixRestore avmr(target);
469
470 GrMatrix m;
471
472 m.setAll(dstRect.width(), 0, dstRect.fLeft,
473 0, dstRect.height(), dstRect.fTop,
474 0, 0, GrMatrix::I()[8]);
475 if (NULL != dstMatrix) {
476 m.postConcat(*dstMatrix);
477 }
478 target->preConcatViewMatrix(m);
479
480 m.setAll(srcRect.width(), 0, srcRect.fLeft,
481 0, srcRect.height(), srcRect.fTop,
482 0, 0, GrMatrix::I()[8]);
483 if (NULL != srcMatrix) {
484 m.postConcat(*srcMatrix);
485 }
486 target->preConcatSamplerMatrix(0, m);
487
488 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
489 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
490#else
491
492 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000493#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +0000494 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000495#else
bsalomon@google.com27847de2011-02-22 20:59:41 +0000496 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
497#endif
498
499 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
500 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
501 srcRects[0] = &srcRect;
502 srcMatrices[0] = srcMatrix;
503
504 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
505#endif
506}
507
508void GrContext::drawVertices(const GrPaint& paint,
509 GrPrimitiveType primitiveType,
510 int vertexCount,
511 const GrPoint positions[],
512 const GrPoint texCoords[],
513 const GrColor colors[],
514 const uint16_t indices[],
515 int indexCount) {
516 GrVertexLayout layout = 0;
517 int vertexSize = sizeof(GrPoint);
518
519 GrDrawTarget::AutoReleaseGeometry geo;
520
521 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
522
523 if (NULL != paint.getTexture()) {
524 if (NULL == texCoords) {
525 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
526 } else {
527 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
528 vertexSize += sizeof(GrPoint);
529 }
530 }
531
532 if (NULL != colors) {
533 layout |= GrDrawTarget::kColor_VertexLayoutBit;
534 vertexSize += sizeof(GrColor);
535 }
536
537 if (sizeof(GrPoint) != vertexSize) {
538 if (!geo.set(target, layout, vertexCount, 0)) {
539 GrPrintf("Failed to get space for vertices!");
540 return;
541 }
542 int texOffsets[GrDrawTarget::kMaxTexCoords];
543 int colorOffset;
544 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
545 texOffsets,
546 &colorOffset);
547 void* curVertex = geo.vertices();
548
549 for (int i = 0; i < vertexCount; ++i) {
550 *((GrPoint*)curVertex) = positions[i];
551
552 if (texOffsets[0] > 0) {
553 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
554 }
555 if (colorOffset > 0) {
556 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
557 }
558 curVertex = (void*)((intptr_t)curVertex + vsize);
559 }
560 } else {
561 target->setVertexSourceToArray(layout, positions, vertexCount);
562 }
563
564 if (NULL != indices) {
565 target->setIndexSourceToArray(indices, indexCount);
566 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
567 } else {
568 target->drawNonIndexed(primitiveType, 0, vertexCount);
569 }
570}
571
572
573////////////////////////////////////////////////////////////////////////////////
574
575void GrContext::drawPath(const GrPaint& paint,
576 GrPathIter* path,
577 GrPathFill fill,
578 const GrPoint* translate) {
579
580
581 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
582
583 GrDrawTarget::StageBitfield enabledStages = 0;
584 if (NULL != paint.getTexture()) {
585 enabledStages |= 1;
586 }
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000587 GrPathRenderer* pr = getPathRenderer(target, path, fill);
588 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000589}
590
bsalomon@google.comd302f142011-03-03 13:54:13 +0000591void GrContext::drawPath(const GrPaint& paint,
592 const GrPath& path,
593 GrPathFill fill,
594 const GrPoint* translate) {
595 GrPath::Iter iter(path);
596 this->drawPath(paint, &iter, fill, translate);
597}
598
599
bsalomon@google.com27847de2011-02-22 20:59:41 +0000600////////////////////////////////////////////////////////////////////////////////
601
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000602void GrContext::flush(int flagsBitfield) {
603 if (kDiscard_FlushBit & flagsBitfield) {
604 fDrawBuffer->reset();
605 } else {
606 flushDrawBuffer();
607 }
608
609 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000610 fGpu->forceRenderTargetFlush();
611 }
612}
613
614void GrContext::flushText() {
615 if (kText_DrawCategory == fLastDrawCategory) {
616 flushDrawBuffer();
617 }
618}
619
620void GrContext::flushDrawBuffer() {
621#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
622 fDrawBuffer->playback(fGpu);
623 fDrawBuffer->reset();
624#endif
625}
626
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000627bool GrContext::readTexturePixels(GrTexture* texture,
628 int left, int top, int width, int height,
629 GrPixelConfig config, void* buffer) {
630
631 // TODO: code read pixels for textures that aren't rendertargets
632
633 this->flush();
634 GrRenderTarget* target = texture->asRenderTarget();
635 if (NULL != target) {
636 return fGpu->readPixels(target,
637 left, top, width, height,
638 config, buffer);
639 } else {
640 return false;
641 }
642}
643
644bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
645 int left, int top, int width, int height,
646 GrPixelConfig config, void* buffer) {
647 uint32_t flushFlags = 0;
648 if (NULL == target) {
649 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
650 }
651
652 this->flush(flushFlags);
653 return fGpu->readPixels(target,
654 left, top, width, height,
655 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656}
657
658void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000659 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000660 size_t stride) {
661
662 // TODO: when underlying api has a direct way to do this we should use it
663 // (e.g. glDrawPixels on desktop GL).
664
665 const GrGpu::TextureDesc desc = {
666 0, GrGpu::kNone_AALevel, width, height, config
667 };
668 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
669 if (NULL == texture) {
670 return;
671 }
672
673 this->flush(true);
674
675 GrAutoUnref aur(texture);
676 GrDrawTarget::AutoStateRestore asr(fGpu);
677
678 GrMatrix matrix;
679 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
680 fGpu->setViewMatrix(matrix);
681
682 fGpu->disableState(GrDrawTarget::kClip_StateBit);
683 fGpu->setAlpha(0xFF);
684 fGpu->setBlendFunc(kOne_BlendCoeff,
685 kZero_BlendCoeff);
686 fGpu->setTexture(0, texture);
687
688 GrSamplerState sampler;
689 sampler.setClampNoFilter();
690 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
691 sampler.setMatrix(matrix);
692 fGpu->setSamplerState(0, sampler);
693
694 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
695 static const int VCOUNT = 4;
696
697 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
698 if (!geo.succeeded()) {
699 return;
700 }
701 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
702 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
703}
704////////////////////////////////////////////////////////////////////////////////
705
706void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
707 target->setTexture(0, paint.getTexture());
708 target->setSamplerState(0, paint.fSampler);
709 target->setColor(paint.fColor);
710
711 if (paint.fDither) {
712 target->enableState(GrDrawTarget::kDither_StateBit);
713 } else {
714 target->disableState(GrDrawTarget::kDither_StateBit);
715 }
716 if (paint.fAntiAlias) {
717 target->enableState(GrDrawTarget::kAntialias_StateBit);
718 } else {
719 target->disableState(GrDrawTarget::kAntialias_StateBit);
720 }
721 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
722}
723
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000724GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000725 DrawCategory category) {
726 if (category != fLastDrawCategory) {
727 flushDrawBuffer();
728 fLastDrawCategory = category;
729 }
730 SetPaint(paint, fGpu);
731 GrDrawTarget* target = fGpu;
732 switch (category) {
733 case kText_DrawCategory:
734#if DEFER_TEXT_RENDERING
735 target = fDrawBuffer;
736 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
737#else
738 target = fGpu;
739#endif
740 break;
741 case kUnbuffered_DrawCategory:
742 target = fGpu;
743 break;
744 case kBuffered_DrawCategory:
745 target = fDrawBuffer;
746 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
747 break;
748 }
749 return target;
750}
751
752////////////////////////////////////////////////////////////////////////////////
753
bsalomon@google.com27847de2011-02-22 20:59:41 +0000754void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000755 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000756 fGpu->setRenderTarget(target);
757}
758
759GrRenderTarget* GrContext::getRenderTarget() {
760 return fGpu->getRenderTarget();
761}
762
763const GrRenderTarget* GrContext::getRenderTarget() const {
764 return fGpu->getRenderTarget();
765}
766
767const GrMatrix& GrContext::getMatrix() const {
768 return fGpu->getViewMatrix();
769}
770
771void GrContext::setMatrix(const GrMatrix& m) {
772 fGpu->setViewMatrix(m);
773}
774
775void GrContext::concatMatrix(const GrMatrix& m) const {
776 fGpu->preConcatViewMatrix(m);
777}
778
779static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
780 intptr_t mask = 1 << shift;
781 if (pred) {
782 bits |= mask;
783 } else {
784 bits &= ~mask;
785 }
786 return bits;
787}
788
789void GrContext::resetStats() {
790 fGpu->resetStats();
791}
792
793const GrGpu::Stats& GrContext::getStats() const {
794 return fGpu->getStats();
795}
796
797void GrContext::printStats() const {
798 fGpu->printStats();
799}
800
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000801GrContext::GrContext(GrGpu* gpu) :
802 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
803 gpu->supportsStencilWrapOps()) {
804
bsalomon@google.com27847de2011-02-22 20:59:41 +0000805 fGpu = gpu;
806 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000807 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000808
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000809 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
810 fGpu->setClipPathRenderer(fCustomPathRenderer);
811
bsalomon@google.com27847de2011-02-22 20:59:41 +0000812 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
813 MAX_TEXTURE_CACHE_BYTES);
814 fFontCache = new GrFontCache(fGpu);
815
816 fLastDrawCategory = kUnbuffered_DrawCategory;
817
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000818 fDrawBuffer = NULL;
819 fDrawBufferVBAllocPool = NULL;
820 fDrawBufferIBAllocPool = NULL;
821
822 this->setupDrawBuffer();
823}
824
825void GrContext::setupDrawBuffer() {
826
827 GrAssert(NULL == fDrawBuffer);
828 GrAssert(NULL == fDrawBufferVBAllocPool);
829 GrAssert(NULL == fDrawBufferIBAllocPool);
830
bsalomon@google.com27847de2011-02-22 20:59:41 +0000831#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000832 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000833 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000834 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
835 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000836 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000837 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000838 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000839 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
840
841 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
842 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000843#endif
844
845#if BATCH_RECT_TO_RECT
846 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
847#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +0000848}
849
850bool GrContext::finalizeTextureKey(GrTextureKey* key,
851 const GrSamplerState& sampler) const {
852 uint32_t bits = 0;
853 uint16_t width = key->width();
854 uint16_t height = key->height();
855
856
857 if (!fGpu->npotTextureTileSupport()) {
858 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
859
860 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
861 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
862
863 if (tiled && !isPow2) {
864 bits |= 1;
865 bits |= sampler.isFilter() ? 2 : 0;
866 }
867 }
868 key->finalize(bits);
869 return 0 != bits;
870}
871
872GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
873 GrDrawTarget* target;
874#if DEFER_TEXT_RENDERING
875 target = prepareToDraw(paint, kText_DrawCategory);
876#else
877 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
878#endif
879 SetPaint(paint, target);
880 return target;
881}
882
883const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
884 return fGpu->getQuadIndexBuffer();
885}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000886
887GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
888 GrPathIter* path,
889 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000890 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000891 fCustomPathRenderer->canDrawPath(target, path, fill)) {
892 return fCustomPathRenderer;
893 } else {
894 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
895 return &fDefaultPathRenderer;
896 }
897}