blob: 84611878e3f3f9b202754406e1138762fbac715d [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"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000018#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000019#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
bsalomon@google.com8295dc12011-05-02 12:53:34 +000029#define ENABLE_OFFSCREEN_AA 0
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000030
bsalomon@google.com27847de2011-02-22 20:59:41 +000031#define DEFER_TEXT_RENDERING 1
32
33#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
34
35static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
36static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
37
38static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
39static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
40
41// We are currently only batching Text and drawRectToRect, both
42// of which use the quad index buffer.
43static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
44static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
45
bsalomon@google.com05ef5102011-05-02 21:14:59 +000046GrContext* GrContext::Create(GrEngine engine,
47 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000048 GrContext* ctx = NULL;
49 GrGpu* fGpu = GrGpu::Create(engine, context3D);
50 if (NULL != fGpu) {
51 ctx = new GrContext(fGpu);
52 fGpu->unref();
53 }
54 return ctx;
55}
56
57GrContext* GrContext::CreateGLShaderContext() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +000058 return GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +000059}
60
61GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000068 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000072}
73
bsalomon@google.com8fe72472011-03-30 21:26:44 +000074void GrContext::contextLost() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000075 // abandon first to so destructors
76 // don't try to free the resources in the API.
77 fGpu->abandonResources();
78
bsalomon@google.com8fe72472011-03-30 21:26:44 +000079 delete fDrawBuffer;
80 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000081
bsalomon@google.com8fe72472011-03-30 21:26:44 +000082 delete fDrawBufferVBAllocPool;
83 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000084
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBufferIBAllocPool;
86 fDrawBufferIBAllocPool = NULL;
87
bsalomon@google.com205d4602011-04-25 12:43:45 +000088 GrSafeSetNull(fAAFillRectIndexBuffer);
89 GrSafeSetNull(fAAStrokeRectIndexBuffer);
90
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 fTextureCache->removeAll();
92 fFontCache->freeAll();
93 fGpu->markContextDirty();
94
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 this->setupDrawBuffer();
96}
97
98void GrContext::resetContext() {
99 fGpu->markContextDirty();
100}
101
102void GrContext::freeGpuResources() {
103 this->flush();
104 fTextureCache->removeAll();
105 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000106}
107
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000108////////////////////////////////////////////////////////////////////////////////
109
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000110enum {
111 kNPOTBit = 0x1,
112 kFilterBit = 0x2,
113 kKeylessBit = 0x4,
114};
115
116bool GrContext::finalizeTextureKey(GrTextureKey* key,
117 const GrSamplerState& sampler,
118 bool keyless) const {
119 uint32_t bits = 0;
120 uint16_t width = key->width();
121 uint16_t height = key->height();
122
123 if (!fGpu->npotTextureTileSupport()) {
124 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
125
126 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
127 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
128
129 if (tiled && !isPow2) {
130 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000131 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000132 bits |= kFilterBit;
133 }
134 }
135 }
136
137 if (keyless) {
138 bits |= kKeylessBit;
139 }
140 key->finalize(bits);
141 return 0 != bits;
142}
143
bsalomon@google.com27847de2011-02-22 20:59:41 +0000144GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
145 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000146 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000147 return fTextureCache->findAndLock(*key);
148}
149
150static void stretchImage(void* dst,
151 int dstW,
152 int dstH,
153 void* src,
154 int srcW,
155 int srcH,
156 int bpp) {
157 GrFixed dx = (srcW << 16) / dstW;
158 GrFixed dy = (srcH << 16) / dstH;
159
160 GrFixed y = dy >> 1;
161
162 int dstXLimit = dstW*bpp;
163 for (int j = 0; j < dstH; ++j) {
164 GrFixed x = dx >> 1;
165 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
166 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
167 for (int i = 0; i < dstXLimit; i += bpp) {
168 memcpy((uint8_t*) dstRow + i,
169 (uint8_t*) srcRow + (x>>16)*bpp,
170 bpp);
171 x += dx;
172 }
173 y += dy;
174 }
175}
176
177GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
178 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000180 void* srcData, size_t rowBytes) {
181 GrAssert(key->width() == desc.fWidth);
182 GrAssert(key->height() == desc.fHeight);
183
184#if GR_DUMP_TEXTURE_UPLOAD
185 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
186#endif
187
188 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000190 if (special) {
191 GrTextureEntry* clampEntry;
192 GrTextureKey clampKey(*key);
193 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
194
195 if (NULL == clampEntry) {
196 clampEntry = createAndLockTexture(&clampKey,
197 GrSamplerState::ClampNoFilter(),
198 desc, srcData, rowBytes);
199 GrAssert(NULL != clampEntry);
200 if (NULL == clampEntry) {
201 return NULL;
202 }
203 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000204 GrTextureDesc rtDesc = desc;
205 rtDesc.fFlags = rtDesc.fFlags |
206 kRenderTarget_GrTextureFlagBit |
207 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000208 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
209 fGpu->minRenderTargetWidth()));
210 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
211 fGpu->minRenderTargetHeight()));
212
213 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
214
215 if (NULL != texture) {
216 GrDrawTarget::AutoStateRestore asr(fGpu);
217 fGpu->setRenderTarget(texture->asRenderTarget());
218 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000219 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000220 fGpu->setViewMatrix(GrMatrix::I());
221 fGpu->setAlpha(0xff);
222 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
223 fGpu->disableState(GrDrawTarget::kDither_StateBit |
224 GrDrawTarget::kClip_StateBit |
225 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000226 GrSamplerState::Filter filter;
227 // if filtering is not desired then we want to ensure all
228 // texels in the resampled image are copies of texels from
229 // the original.
230 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
231 filter = GrSamplerState::kNearest_Filter;
232 } else {
233 filter = GrSamplerState::kBilinear_Filter;
234 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000235 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
236 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000237 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000238 fGpu->setSamplerState(0, stretchSampler);
239
240 static const GrVertexLayout layout =
241 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
242 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
243
244 if (arg.succeeded()) {
245 GrPoint* verts = (GrPoint*) arg.vertices();
246 verts[0].setIRectFan(0, 0,
247 texture->width(),
248 texture->height(),
249 2*sizeof(GrPoint));
250 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
251 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
252 0, 4);
253 entry = fTextureCache->createAndLock(*key, texture);
254 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000255 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000256 } else {
257 // TODO: Our CPU stretch doesn't filter. But we create separate
258 // stretched textures when the sampler state is either filtered or
259 // not. Either implement filtered stretch blit on CPU or just create
260 // one when FBO case fails.
261
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000262 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000263 // no longer need to clamp at min RT size.
264 rtDesc.fWidth = GrNextPow2(desc.fWidth);
265 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000266 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000267 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
268 rtDesc.fWidth *
269 rtDesc.fHeight);
270 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
271 srcData, desc.fWidth, desc.fHeight, bpp);
272
273 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
274
275 GrTexture* texture = fGpu->createTexture(rtDesc,
276 stretchedPixels.get(),
277 stretchedRowBytes);
278 GrAssert(NULL != texture);
279 entry = fTextureCache->createAndLock(*key, texture);
280 }
281 fTextureCache->unlock(clampEntry);
282
283 } else {
284 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
285 if (NULL != texture) {
286 entry = fTextureCache->createAndLock(*key, texture);
287 } else {
288 entry = NULL;
289 }
290 }
291 return entry;
292}
293
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000294GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000295 uint32_t p0 = desc.fFormat;
296 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
297 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000298 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
299
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000300 GrTextureEntry* entry = fTextureCache->findAndLock(key);
301 if (NULL == entry) {
302 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
303 if (NULL != texture) {
304 entry = fTextureCache->createAndLock(key, texture);
305 }
306 }
307 // If the caller gives us the same desc/sampler twice we don't want
308 // to return the same texture the second time (unless it was previously
309 // released). So we detach the entry from the cache and reattach at release.
310 if (NULL != entry) {
311 fTextureCache->detach(entry);
312 }
313 return entry;
314}
315
bsalomon@google.com27847de2011-02-22 20:59:41 +0000316void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000317 if (kKeylessBit & entry->key().getPrivateBits()) {
318 fTextureCache->reattachAndUnlock(entry);
319 } else {
320 fTextureCache->unlock(entry);
321 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000322}
323
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000324GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000325 void* srcData,
326 size_t rowBytes) {
327 return fGpu->createTexture(desc, srcData, rowBytes);
328}
329
330void GrContext::getTextureCacheLimits(int* maxTextures,
331 size_t* maxTextureBytes) const {
332 fTextureCache->getLimits(maxTextures, maxTextureBytes);
333}
334
335void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
336 fTextureCache->setLimits(maxTextures, maxTextureBytes);
337}
338
339int GrContext::getMaxTextureDimension() {
340 return fGpu->maxTextureDimension();
341}
342
343///////////////////////////////////////////////////////////////////////////////
344
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000345GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
346 // validate flags here so that GrGpu subclasses don't have to check
347 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
348 0 != desc.fRenderTargetFlags) {
349 return NULL;
350 }
351 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
352 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
353 return NULL;
354 }
355 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
356 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
357 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
358 return NULL;
359 }
360 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000361}
362
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000363GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,
364 int stencilBits,
365 bool isMultisampled,
366 int width, int height) {
367#if GR_DEBUG
368 GrPrintf("Using deprecated createPlatformRenderTarget API.");
369#endif
370 return fGpu->createPlatformRenderTarget(platformRenderTarget,
371 stencilBits, isMultisampled,
372 width, height);
373}
374
375GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
376#if GR_DEBUG
377 GrPrintf("Using deprecated createRenderTargetFrom3DApiState API.");
378#endif
379 return fGpu->createRenderTargetFrom3DApiState();
380}
381
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000382///////////////////////////////////////////////////////////////////////////////
383
bsalomon@google.com27847de2011-02-22 20:59:41 +0000384bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
385 int width, int height) {
386 if (!fGpu->supports8BitPalette()) {
387 return false;
388 }
389
390
391 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
392
393 if (!isPow2) {
394 if (!fGpu->npotTextureSupport()) {
395 return false;
396 }
397
398 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
399 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
400 if (tiled && !fGpu->npotTextureTileSupport()) {
401 return false;
402 }
403 }
404 return true;
405}
406
407////////////////////////////////////////////////////////////////////////////////
408
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000409const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
410
bsalomon@google.com27847de2011-02-22 20:59:41 +0000411void GrContext::setClip(const GrClip& clip) {
412 fGpu->setClip(clip);
413 fGpu->enableState(GrDrawTarget::kClip_StateBit);
414}
415
416void GrContext::setClip(const GrIRect& rect) {
417 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000418 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000419 fGpu->setClip(clip);
420}
421
422////////////////////////////////////////////////////////////////////////////////
423
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000424void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000425 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000426 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000427}
428
429void GrContext::drawPaint(const GrPaint& paint) {
430 // set rect to be big enough to fill the space, but not super-huge, so we
431 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000432 GrRect r;
433 r.setLTRB(0, 0,
434 GrIntToScalar(getRenderTarget()->width()),
435 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000436 GrMatrix inverse;
437 if (fGpu->getViewInverse(&inverse)) {
438 inverse.mapRect(&r);
439 } else {
440 GrPrintf("---- fGpu->getViewInverse failed\n");
441 }
442 this->drawRect(paint, r);
443}
444
bsalomon@google.com205d4602011-04-25 12:43:45 +0000445////////////////////////////////////////////////////////////////////////////////
446
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000447bool GrContext::doOffscreenAA(GrDrawTarget* target,
448 const GrPaint& paint,
449 bool isLines) const {
450#if !ENABLE_OFFSCREEN_AA
451 return false;
452#else
453 if (!paint.fAntiAlias) {
454 return false;
455 }
456 if (isLines && fGpu->supportsAALines()) {
457 return false;
458 }
459 if (target->getRenderTarget()->isMultisampled()) {
460 return false;
461 }
462 // we have to be sure that the blend equation is expressible
463 // as simple src / dst coeffecients when the source
464 // is already modulated by the coverage fraction.
465 // We could use dual-source blending to get the correct per-pixel
466 // dst coeffecient for the remaining cases.
467 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
468 kOne_BlendCoeff != paint.fDstBlendCoeff &&
469 kISA_BlendCoeff != paint.fDstBlendCoeff) {
470 return false;
471 }
472 return true;
473#endif
474}
475
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000476bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
477 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000478 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000479 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000480 GrAssert(ENABLE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000481
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000482 GrAssert(NULL == record->fEntry0);
483 GrAssert(NULL == record->fEntry1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000484
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000485 int boundW = boundRect.width();
486 int boundH = boundRect.height();
487 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000488
489 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000490 if (requireStencil) {
491 desc.fFlags = kRenderTarget_GrTextureFlagBit;
492 } else {
493 desc.fFlags = kRenderTarget_GrTextureFlagBit |
494 kNoStencil_GrTextureFlagBit;
495 }
496
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000497 desc.fFormat = kRGBA_8888_GrPixelConfig;
498
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000499 int scale;
500 // Using MSAA seems to be slower for some yet unknown reason.
501 if (false && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000502 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000503 scale = GR_Scalar1;
504 desc.fAALevel = kMed_GrAALevel;
505 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000506 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
507 OffscreenRecord::k4x4SinglePass_Downsample :
508 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000509 scale = 4;
510 desc.fAALevel = kNone_GrAALevel;
511 }
512
513 desc.fWidth = scale * size;
514 desc.fHeight = scale * size;
515
516 record->fEntry0 = this->lockKeylessTexture(desc);
517
518 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000519 return false;
520 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000521
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000522 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000523 desc.fWidth /= 2;
524 desc.fHeight /= 2;
525 record->fEntry1 = this->lockKeylessTexture(desc);
526 if (NULL == record->fEntry1) {
527 this->unlockTexture(record->fEntry0);
528 record->fEntry0 = NULL;
529 return false;
530 }
531 }
532
533 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
534 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000535
536 target->saveCurrentDrawState(&record->fSavedState);
537
538 GrPaint tempPaint;
539 tempPaint.reset();
540 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000541 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000542
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000543 GrMatrix transM;
544 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
545 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000546 GrMatrix scaleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000547 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000548 target->postConcatViewMatrix(scaleM);
549
550 // clip gets applied in second pass
551 target->disableState(GrDrawTarget::kClip_StateBit);
552
reed@google.com20efde72011-05-09 17:00:02 +0000553 GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000554 target->clear(&clear, 0x0);
555
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000556 return true;
557}
558
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000559void GrContext::offscreenAAPass2(GrDrawTarget* target,
560 const GrPaint& paint,
561 const GrIRect& boundRect,
562 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000563
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000564 GrAssert(NULL != record->fEntry0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000565
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000566 GrSamplerState::Filter filter;
567 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
568 filter = GrSamplerState::k4x4Downsample_Filter;
569 } else {
570 filter = GrSamplerState::kBilinear_Filter;
571 }
572
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000573 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000574 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000575 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000576
577 GrTexture* src = record->fEntry0->texture();
578 int scale;
579
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000580 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
581 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000582 scale = 2;
583 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
584
585 // Do 2x2 downsample from first to second
586 target->setTexture(kOffscreenStage, src);
587 target->setRenderTarget(dst);
588 target->setViewMatrix(GrMatrix::I());
589 sampleM.setScale(scale * GR_Scalar1 / src->width(),
590 scale * GR_Scalar1 / src->height());
591 sampler.setMatrix(sampleM);
592 target->setSamplerState(kOffscreenStage, sampler);
reed@google.com20efde72011-05-09 17:00:02 +0000593 GrRect rect = SkRect::MakeWH(scale * boundRect.width(),
594 scale * boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000595 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
596
597 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000598 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000599 scale = 1;
reed@google.com20efde72011-05-09 17:00:02 +0000600 GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000601 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000602 } else {
603 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
604 record->fDownsample);
605 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000606 }
607
608 // setup for draw back to main RT
609 target->restoreDrawState(record->fSavedState);
610 if (NULL != paint.getTexture()) {
611 GrMatrix invVM;
612 if (target->getViewInverse(&invVM)) {
613 target->preConcatSamplerMatrix(0, invVM);
614 }
615 }
616 target->setViewMatrix(GrMatrix::I());
617
618 target->setTexture(kOffscreenStage, src);
619 sampleM.setScale(scale * GR_Scalar1 / src->width(),
620 scale * GR_Scalar1 / src->height());
621 sampler.setMatrix(sampleM);
622 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
623 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000624 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000625
reed@google.com20efde72011-05-09 17:00:02 +0000626 GrRect dstRect;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000627 int stages = (1 << kOffscreenStage) | (NULL == paint.getTexture() ? 0 : 1);
reed@google.com20efde72011-05-09 17:00:02 +0000628 dstRect.set(boundRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000629 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000630
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000631 this->unlockTexture(record->fEntry0);
632 record->fEntry0 = NULL;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000633 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000634 this->unlockTexture(record->fEntry1);
635 record->fEntry1 = NULL;
636 }
637 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000638}
639
640////////////////////////////////////////////////////////////////////////////////
641
bsalomon@google.com27847de2011-02-22 20:59:41 +0000642/* create a triangle strip that strokes the specified triangle. There are 8
643 unique vertices, but we repreat the last 2 to close up. Alternatively we
644 could use an indices array, and then only send 8 verts, but not sure that
645 would be faster.
646 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000647static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000648 GrScalar width) {
649 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000650 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000651
652 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
653 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
654 verts[2].set(rect.fRight - rad, rect.fTop + rad);
655 verts[3].set(rect.fRight + rad, rect.fTop - rad);
656 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
657 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
658 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
659 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
660 verts[8] = verts[0];
661 verts[9] = verts[1];
662}
663
bsalomon@google.com205d4602011-04-25 12:43:45 +0000664static GrColor getColorForMesh(const GrPaint& paint) {
665 if (NULL == paint.getTexture()) {
666 return paint.fColor;
667 } else {
668 unsigned a = GrColorUnpackA(paint.fColor);
669 return GrColorPackRGBA(a, a, a, a);
670 }
671}
672
673static void setInsetFan(GrPoint* pts, size_t stride,
674 const GrRect& r, GrScalar dx, GrScalar dy) {
675 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
676}
677
678static const uint16_t gFillAARectIdx[] = {
679 0, 1, 5, 5, 4, 0,
680 1, 2, 6, 6, 5, 1,
681 2, 3, 7, 7, 6, 2,
682 3, 0, 4, 4, 7, 3,
683 4, 5, 6, 6, 7, 4,
684};
685
686int GrContext::aaFillRectIndexCount() const {
687 return GR_ARRAY_COUNT(gFillAARectIdx);
688}
689
690GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
691 if (NULL == fAAFillRectIndexBuffer) {
692 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
693 false);
694 GrAssert(NULL != fAAFillRectIndexBuffer);
695#if GR_DEBUG
696 bool updated =
697#endif
698 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
699 sizeof(gFillAARectIdx));
700 GR_DEBUGASSERT(updated);
701 }
702 return fAAFillRectIndexBuffer;
703}
704
705static const uint16_t gStrokeAARectIdx[] = {
706 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
707 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
708 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
709 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
710
711 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
712 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
713 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
714 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
715
716 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
717 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
718 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
719 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
720};
721
722int GrContext::aaStrokeRectIndexCount() const {
723 return GR_ARRAY_COUNT(gStrokeAARectIdx);
724}
725
726GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
727 if (NULL == fAAStrokeRectIndexBuffer) {
728 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
729 false);
730 GrAssert(NULL != fAAStrokeRectIndexBuffer);
731#if GR_DEBUG
732 bool updated =
733#endif
734 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
735 sizeof(gStrokeAARectIdx));
736 GR_DEBUGASSERT(updated);
737 }
738 return fAAStrokeRectIndexBuffer;
739}
740
741void GrContext::fillAARect(GrDrawTarget* target,
742 const GrPaint& paint,
743 const GrRect& devRect) {
744
745 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
746 if (NULL != paint.getTexture()) {
747 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
748 }
749
750 size_t vsize = GrDrawTarget::VertexSize(layout);
751
752 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
753
754 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
755
756 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
757 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
758
759 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
760 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
761
762 verts += sizeof(GrPoint);
763 for (int i = 0; i < 4; ++i) {
764 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
765 }
766
767 GrColor innerColor = getColorForMesh(paint);
768 verts += 4 * vsize;
769 for (int i = 0; i < 4; ++i) {
770 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
771 }
772
773 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
774
775 target->drawIndexed(kTriangles_PrimitiveType, 0,
776 0, 8, this->aaFillRectIndexCount());
777}
778
779void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
780 const GrRect& devRect, const GrVec& devStrokeSize) {
781 const GrScalar& dx = devStrokeSize.fX;
782 const GrScalar& dy = devStrokeSize.fY;
783 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
784 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
785
786 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
787
788 if (NULL != paint.getTexture()) {
789 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
790 }
791
792 GrScalar spare;
793 {
794 GrScalar w = devRect.width() - dx;
795 GrScalar h = devRect.height() - dy;
796 spare = GrMin(w, h);
797 }
798
799 if (spare <= 0) {
800 GrRect r(devRect);
801 r.inset(-rx, -ry);
802 fillAARect(target, paint, r);
803 return;
804 }
805
806 size_t vsize = GrDrawTarget::VertexSize(layout);
807
808 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
809
810 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
811
812 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
813 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
814 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
815 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
816
817 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
818 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
819 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
820 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
821
822 verts += sizeof(GrPoint);
823 for (int i = 0; i < 4; ++i) {
824 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
825 }
826
827 GrColor innerColor = getColorForMesh(paint);
828 verts += 4 * vsize;
829 for (int i = 0; i < 8; ++i) {
830 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
831 }
832
833 verts += 8 * vsize;
834 for (int i = 0; i < 8; ++i) {
835 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
836 }
837
838 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
839 target->drawIndexed(kTriangles_PrimitiveType,
840 0, 0, 16, aaStrokeRectIndexCount());
841}
842
reed@google.com20efde72011-05-09 17:00:02 +0000843/**
844 * Returns true if the rects edges are integer-aligned.
845 */
846static bool isIRect(const GrRect& r) {
847 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
848 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
849}
850
bsalomon@google.com205d4602011-04-25 12:43:45 +0000851static bool apply_aa_to_rect(GrDrawTarget* target,
852 GrGpu* gpu,
853 const GrPaint& paint,
854 const GrRect& rect,
855 GrScalar width,
856 const GrMatrix* matrix,
857 GrMatrix* combinedMatrix,
858 GrRect* devRect) {
859 // we use a simple alpha ramp to do aa on axis-aligned rects
860 // do AA with alpha ramp if the caller requested AA, the rect
861 // will be axis-aligned,the render target is not
862 // multisampled, and the rect won't land on integer coords.
863
864 if (!paint.fAntiAlias) {
865 return false;
866 }
867
868 if (target->getRenderTarget()->isMultisampled()) {
869 return false;
870 }
871
872 if (0 == width && gpu->supportsAALines()) {
873 return false;
874 }
875
876 if (!target->getViewMatrix().preservesAxisAlignment()) {
877 return false;
878 }
879
880 if (NULL != matrix &&
881 !matrix->preservesAxisAlignment()) {
882 return false;
883 }
884
885 *combinedMatrix = target->getViewMatrix();
886 if (NULL != matrix) {
887 combinedMatrix->preConcat(*matrix);
888 GrAssert(combinedMatrix->preservesAxisAlignment());
889 }
890
891 combinedMatrix->mapRect(devRect, rect);
892 devRect->sort();
893
894 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000895 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000896 } else {
897 return true;
898 }
899}
900
bsalomon@google.com27847de2011-02-22 20:59:41 +0000901void GrContext::drawRect(const GrPaint& paint,
902 const GrRect& rect,
903 GrScalar width,
904 const GrMatrix* matrix) {
905
906 bool textured = NULL != paint.getTexture();
907
908 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
909
bsalomon@google.com205d4602011-04-25 12:43:45 +0000910 GrRect devRect = rect;
911 GrMatrix combinedMatrix;
912 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
913 &combinedMatrix, &devRect);
914
915 if (doAA) {
916 GrDrawTarget::AutoViewMatrixRestore avm(target);
917 if (textured) {
918 GrMatrix inv;
919 if (combinedMatrix.invert(&inv)) {
920 target->preConcatSamplerMatrix(0, inv);
921 }
922 }
923 target->setViewMatrix(GrMatrix::I());
924 if (width >= 0) {
925 GrVec strokeSize;;
926 if (width > 0) {
927 strokeSize.set(width, width);
928 combinedMatrix.mapVec(&strokeSize);
929 strokeSize.setAbs(strokeSize);
930 } else {
931 strokeSize.set(GR_Scalar1, GR_Scalar1);
932 }
933 strokeAARect(target, paint, devRect, strokeSize);
934 } else {
935 fillAARect(target, paint, devRect);
936 }
937 return;
938 }
939
bsalomon@google.com27847de2011-02-22 20:59:41 +0000940 if (width >= 0) {
941 // TODO: consider making static vertex buffers for these cases.
942 // Hairline could be done by just adding closing vertex to
943 // unitSquareVertexBuffer()
bsalomon@google.com205d4602011-04-25 12:43:45 +0000944 GrVertexLayout layout = textured ?
945 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
946 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000947 static const int worstCaseVertCount = 10;
948 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
949
950 if (!geo.succeeded()) {
951 return;
952 }
953
954 GrPrimitiveType primType;
955 int vertCount;
956 GrPoint* vertex = geo.positions();
957
958 if (width > 0) {
959 vertCount = 10;
960 primType = kTriangleStrip_PrimitiveType;
961 setStrokeRectStrip(vertex, rect, width);
962 } else {
963 // hairline
964 vertCount = 5;
965 primType = kLineStrip_PrimitiveType;
966 vertex[0].set(rect.fLeft, rect.fTop);
967 vertex[1].set(rect.fRight, rect.fTop);
968 vertex[2].set(rect.fRight, rect.fBottom);
969 vertex[3].set(rect.fLeft, rect.fBottom);
970 vertex[4].set(rect.fLeft, rect.fTop);
971 }
972
973 GrDrawTarget::AutoViewMatrixRestore avmr;
974 if (NULL != matrix) {
975 avmr.set(target);
976 target->preConcatViewMatrix(*matrix);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000977 if (textured) {
978 target->preConcatSamplerMatrix(0, *matrix);
979 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000980 }
981
982 target->drawNonIndexed(primType, 0, vertCount);
983 } else {
984 #if GR_STATIC_RECT_VB
985 GrVertexLayout layout = (textured) ?
986 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
987 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000988 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000989 fGpu->getUnitSquareVertexBuffer());
990 GrDrawTarget::AutoViewMatrixRestore avmr(target);
991 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000992 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000993 0, rect.height(), rect.fTop,
994 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000995
996 if (NULL != matrix) {
997 m.postConcat(*matrix);
998 }
999
1000 target->preConcatViewMatrix(m);
1001
1002 if (textured) {
1003 target->preConcatSamplerMatrix(0, m);
1004 }
1005 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1006 #else
1007 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
1008 #endif
1009 }
1010}
1011
1012void GrContext::drawRectToRect(const GrPaint& paint,
1013 const GrRect& dstRect,
1014 const GrRect& srcRect,
1015 const GrMatrix* dstMatrix,
1016 const GrMatrix* srcMatrix) {
1017
1018 if (NULL == paint.getTexture()) {
1019 drawRect(paint, dstRect, -1, dstMatrix);
1020 return;
1021 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001022
bsalomon@google.com27847de2011-02-22 20:59:41 +00001023 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1024
1025#if GR_STATIC_RECT_VB
1026 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1027
1028 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1029 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1030
1031 GrMatrix m;
1032
1033 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1034 0, dstRect.height(), dstRect.fTop,
1035 0, 0, GrMatrix::I()[8]);
1036 if (NULL != dstMatrix) {
1037 m.postConcat(*dstMatrix);
1038 }
1039 target->preConcatViewMatrix(m);
1040
1041 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1042 0, srcRect.height(), srcRect.fTop,
1043 0, 0, GrMatrix::I()[8]);
1044 if (NULL != srcMatrix) {
1045 m.postConcat(*srcMatrix);
1046 }
1047 target->preConcatSamplerMatrix(0, m);
1048
1049 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1050 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1051#else
1052
1053 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001054#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001055 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001056#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001057 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1058#endif
1059
1060 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1061 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1062 srcRects[0] = &srcRect;
1063 srcMatrices[0] = srcMatrix;
1064
1065 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1066#endif
1067}
1068
1069void GrContext::drawVertices(const GrPaint& paint,
1070 GrPrimitiveType primitiveType,
1071 int vertexCount,
1072 const GrPoint positions[],
1073 const GrPoint texCoords[],
1074 const GrColor colors[],
1075 const uint16_t indices[],
1076 int indexCount) {
1077 GrVertexLayout layout = 0;
1078 int vertexSize = sizeof(GrPoint);
1079
1080 GrDrawTarget::AutoReleaseGeometry geo;
1081
1082 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1083
1084 if (NULL != paint.getTexture()) {
1085 if (NULL == texCoords) {
1086 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1087 } else {
1088 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
1089 vertexSize += sizeof(GrPoint);
1090 }
1091 }
1092
1093 if (NULL != colors) {
1094 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1095 vertexSize += sizeof(GrColor);
1096 }
1097
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001098 bool doAA = false;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001099 OffscreenRecord record;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001100 GrIRect bounds;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001101
bsalomon@google.com27847de2011-02-22 20:59:41 +00001102 if (sizeof(GrPoint) != vertexSize) {
1103 if (!geo.set(target, layout, vertexCount, 0)) {
1104 GrPrintf("Failed to get space for vertices!");
1105 return;
1106 }
1107 int texOffsets[GrDrawTarget::kMaxTexCoords];
1108 int colorOffset;
1109 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1110 texOffsets,
1111 &colorOffset);
1112 void* curVertex = geo.vertices();
1113
1114 for (int i = 0; i < vertexCount; ++i) {
1115 *((GrPoint*)curVertex) = positions[i];
1116
1117 if (texOffsets[0] > 0) {
1118 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1119 }
1120 if (colorOffset > 0) {
1121 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1122 }
1123 curVertex = (void*)((intptr_t)curVertex + vsize);
1124 }
1125 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001126 // we don't do offscreen AA when we have per-vertex tex coords or colors
1127 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1128 GrRect b;
1129 b.setBounds(positions, vertexCount);
1130 target->getViewMatrix().mapRect(&b);
1131 b.roundOut(&bounds);
1132
1133 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1134 doAA = true;
1135 }
1136 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001137 target->setVertexSourceToArray(layout, positions, vertexCount);
1138 }
1139
1140 if (NULL != indices) {
1141 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001142 }
1143
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001144 if (NULL != indices) {
1145 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001147 target->drawNonIndexed(primitiveType, 0, vertexCount);
1148 }
1149
1150 if (doAA) {
1151 this->offscreenAAPass2(target, paint, bounds, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001152 }
1153}
1154
1155
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001156///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001157
1158void GrContext::drawPath(const GrPaint& paint,
1159 GrPathIter* path,
1160 GrPathFill fill,
1161 const GrPoint* translate) {
1162
bsalomon@google.com27847de2011-02-22 20:59:41 +00001163 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001164 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001165
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001166 if (!IsFillInverted(fill) && // will be relaxed soon
1167 !pr->supportsAA(target, path, fill) &&
1168 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001169
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001170 OffscreenRecord record;
1171 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001172
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001173 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001174 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1175 target->getRenderTarget()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001176 if (target->getClip().hasConservativeBounds()) {
1177 GrIRect clipIBounds;
1178 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001179 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001180 return;
1181 }
1182 }
1183 GrRect pathBounds;
1184 if (path->getConservativeBounds(&pathBounds)) {
1185 GrIRect pathIBounds;
1186 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1187 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001188 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001189 return;
1190 }
1191 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001192
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001193 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1194 pr->drawPath(target, 0, path, fill, translate);
1195 this->offscreenAAPass2(target, paint, bound, &record);
1196 return;
1197 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001198 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001199 GrDrawTarget::StageBitfield enabledStages = 0;
1200 if (NULL != paint.getTexture()) {
1201 enabledStages |= 1;
1202 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001203
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001204 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001205}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001206
bsalomon@google.comd302f142011-03-03 13:54:13 +00001207void GrContext::drawPath(const GrPaint& paint,
1208 const GrPath& path,
1209 GrPathFill fill,
1210 const GrPoint* translate) {
1211 GrPath::Iter iter(path);
1212 this->drawPath(paint, &iter, fill, translate);
1213}
1214
1215
bsalomon@google.com27847de2011-02-22 20:59:41 +00001216////////////////////////////////////////////////////////////////////////////////
1217
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001218void GrContext::flush(int flagsBitfield) {
1219 if (kDiscard_FlushBit & flagsBitfield) {
1220 fDrawBuffer->reset();
1221 } else {
1222 flushDrawBuffer();
1223 }
1224
1225 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001226 fGpu->forceRenderTargetFlush();
1227 }
1228}
1229
1230void GrContext::flushText() {
1231 if (kText_DrawCategory == fLastDrawCategory) {
1232 flushDrawBuffer();
1233 }
1234}
1235
1236void GrContext::flushDrawBuffer() {
1237#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1238 fDrawBuffer->playback(fGpu);
1239 fDrawBuffer->reset();
1240#endif
1241}
1242
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001243bool GrContext::readTexturePixels(GrTexture* texture,
1244 int left, int top, int width, int height,
1245 GrPixelConfig config, void* buffer) {
1246
1247 // TODO: code read pixels for textures that aren't rendertargets
1248
1249 this->flush();
1250 GrRenderTarget* target = texture->asRenderTarget();
1251 if (NULL != target) {
1252 return fGpu->readPixels(target,
1253 left, top, width, height,
1254 config, buffer);
1255 } else {
1256 return false;
1257 }
1258}
1259
1260bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1261 int left, int top, int width, int height,
1262 GrPixelConfig config, void* buffer) {
1263 uint32_t flushFlags = 0;
1264 if (NULL == target) {
1265 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1266 }
1267
1268 this->flush(flushFlags);
1269 return fGpu->readPixels(target,
1270 left, top, width, height,
1271 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001272}
1273
1274void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001275 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001276 size_t stride) {
1277
1278 // TODO: when underlying api has a direct way to do this we should use it
1279 // (e.g. glDrawPixels on desktop GL).
1280
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001281 const GrTextureDesc desc = {
1282 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001283 };
1284 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1285 if (NULL == texture) {
1286 return;
1287 }
1288
1289 this->flush(true);
1290
1291 GrAutoUnref aur(texture);
1292 GrDrawTarget::AutoStateRestore asr(fGpu);
1293
1294 GrMatrix matrix;
1295 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1296 fGpu->setViewMatrix(matrix);
1297
1298 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1299 fGpu->setAlpha(0xFF);
1300 fGpu->setBlendFunc(kOne_BlendCoeff,
1301 kZero_BlendCoeff);
1302 fGpu->setTexture(0, texture);
1303
1304 GrSamplerState sampler;
1305 sampler.setClampNoFilter();
1306 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1307 sampler.setMatrix(matrix);
1308 fGpu->setSamplerState(0, sampler);
1309
1310 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1311 static const int VCOUNT = 4;
1312
1313 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1314 if (!geo.succeeded()) {
1315 return;
1316 }
1317 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1318 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1319}
1320////////////////////////////////////////////////////////////////////////////////
1321
1322void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1323 target->setTexture(0, paint.getTexture());
1324 target->setSamplerState(0, paint.fSampler);
1325 target->setColor(paint.fColor);
1326
1327 if (paint.fDither) {
1328 target->enableState(GrDrawTarget::kDither_StateBit);
1329 } else {
1330 target->disableState(GrDrawTarget::kDither_StateBit);
1331 }
1332 if (paint.fAntiAlias) {
1333 target->enableState(GrDrawTarget::kAntialias_StateBit);
1334 } else {
1335 target->disableState(GrDrawTarget::kAntialias_StateBit);
1336 }
1337 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1338}
1339
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001340GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001341 DrawCategory category) {
1342 if (category != fLastDrawCategory) {
1343 flushDrawBuffer();
1344 fLastDrawCategory = category;
1345 }
1346 SetPaint(paint, fGpu);
1347 GrDrawTarget* target = fGpu;
1348 switch (category) {
1349 case kText_DrawCategory:
1350#if DEFER_TEXT_RENDERING
1351 target = fDrawBuffer;
1352 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1353#else
1354 target = fGpu;
1355#endif
1356 break;
1357 case kUnbuffered_DrawCategory:
1358 target = fGpu;
1359 break;
1360 case kBuffered_DrawCategory:
1361 target = fDrawBuffer;
1362 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1363 break;
1364 }
1365 return target;
1366}
1367
1368////////////////////////////////////////////////////////////////////////////////
1369
bsalomon@google.com27847de2011-02-22 20:59:41 +00001370void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001371 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372 fGpu->setRenderTarget(target);
1373}
1374
1375GrRenderTarget* GrContext::getRenderTarget() {
1376 return fGpu->getRenderTarget();
1377}
1378
1379const GrRenderTarget* GrContext::getRenderTarget() const {
1380 return fGpu->getRenderTarget();
1381}
1382
1383const GrMatrix& GrContext::getMatrix() const {
1384 return fGpu->getViewMatrix();
1385}
1386
1387void GrContext::setMatrix(const GrMatrix& m) {
1388 fGpu->setViewMatrix(m);
1389}
1390
1391void GrContext::concatMatrix(const GrMatrix& m) const {
1392 fGpu->preConcatViewMatrix(m);
1393}
1394
1395static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1396 intptr_t mask = 1 << shift;
1397 if (pred) {
1398 bits |= mask;
1399 } else {
1400 bits &= ~mask;
1401 }
1402 return bits;
1403}
1404
1405void GrContext::resetStats() {
1406 fGpu->resetStats();
1407}
1408
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001409const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410 return fGpu->getStats();
1411}
1412
1413void GrContext::printStats() const {
1414 fGpu->printStats();
1415}
1416
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001417GrContext::GrContext(GrGpu* gpu) :
1418 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1419 gpu->supportsStencilWrapOps()) {
1420
bsalomon@google.com27847de2011-02-22 20:59:41 +00001421 fGpu = gpu;
1422 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001423 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001424
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001425 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1426 fGpu->setClipPathRenderer(fCustomPathRenderer);
1427
bsalomon@google.com27847de2011-02-22 20:59:41 +00001428 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1429 MAX_TEXTURE_CACHE_BYTES);
1430 fFontCache = new GrFontCache(fGpu);
1431
1432 fLastDrawCategory = kUnbuffered_DrawCategory;
1433
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001434 fDrawBuffer = NULL;
1435 fDrawBufferVBAllocPool = NULL;
1436 fDrawBufferIBAllocPool = NULL;
1437
bsalomon@google.com205d4602011-04-25 12:43:45 +00001438 fAAFillRectIndexBuffer = NULL;
1439 fAAStrokeRectIndexBuffer = NULL;
1440
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001441 this->setupDrawBuffer();
1442}
1443
1444void GrContext::setupDrawBuffer() {
1445
1446 GrAssert(NULL == fDrawBuffer);
1447 GrAssert(NULL == fDrawBufferVBAllocPool);
1448 GrAssert(NULL == fDrawBufferIBAllocPool);
1449
bsalomon@google.com27847de2011-02-22 20:59:41 +00001450#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001451 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001452 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001453 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1454 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001455 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001456 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001457 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001458 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1459
1460 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1461 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001462#endif
1463
1464#if BATCH_RECT_TO_RECT
1465 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1466#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001467}
1468
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1470 GrDrawTarget* target;
1471#if DEFER_TEXT_RENDERING
1472 target = prepareToDraw(paint, kText_DrawCategory);
1473#else
1474 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1475#endif
1476 SetPaint(paint, target);
1477 return target;
1478}
1479
1480const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1481 return fGpu->getQuadIndexBuffer();
1482}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001483
1484GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1485 GrPathIter* path,
1486 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001487 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001488 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1489 return fCustomPathRenderer;
1490 } else {
1491 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1492 return &fDefaultPathRenderer;
1493 }
1494}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001495