blob: 3a4233a3464bed2ea39d7ca07296b2effc5d47af [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"
bsalomon@google.com27847de2011-02-22 20:59:41 +000022#include "GrClipIterator.h"
23#include "GrIndexBuffer.h"
24#include "GrInOrderDrawBuffer.h"
25#include "GrBufferAllocPool.h"
26#include "GrPathRenderer.h"
27
bsalomon@google.com8295dc12011-05-02 12:53:34 +000028#define ENABLE_OFFSCREEN_AA 0
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000029
bsalomon@google.com27847de2011-02-22 20:59:41 +000030#define DEFER_TEXT_RENDERING 1
31
32#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
33
34static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
35static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
36
37static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
38static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
39
40// We are currently only batching Text and drawRectToRect, both
41// of which use the quad index buffer.
42static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
43static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
44
bsalomon@google.com05ef5102011-05-02 21:14:59 +000045GrContext* GrContext::Create(GrEngine engine,
46 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000047 GrContext* ctx = NULL;
48 GrGpu* fGpu = GrGpu::Create(engine, context3D);
49 if (NULL != fGpu) {
50 ctx = new GrContext(fGpu);
51 fGpu->unref();
52 }
53 return ctx;
54}
55
56GrContext* GrContext::CreateGLShaderContext() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +000057 return GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +000058}
59
60GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000061 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000062 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.com205d4602011-04-25 12:43:45 +000068 GrSafeUnref(fAAFillRectIndexBuffer);
69 GrSafeUnref(fAAStrokeRectIndexBuffer);
70 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000071}
72
bsalomon@google.com8fe72472011-03-30 21:26:44 +000073void GrContext::contextLost() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000074 // abandon first to so destructors
75 // don't try to free the resources in the API.
76 fGpu->abandonResources();
77
bsalomon@google.com8fe72472011-03-30 21:26:44 +000078 delete fDrawBuffer;
79 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000080
bsalomon@google.com8fe72472011-03-30 21:26:44 +000081 delete fDrawBufferVBAllocPool;
82 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000083
bsalomon@google.com8fe72472011-03-30 21:26:44 +000084 delete fDrawBufferIBAllocPool;
85 fDrawBufferIBAllocPool = NULL;
86
bsalomon@google.com205d4602011-04-25 12:43:45 +000087 GrSafeSetNull(fAAFillRectIndexBuffer);
88 GrSafeSetNull(fAAStrokeRectIndexBuffer);
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 fTextureCache->removeAll();
91 fFontCache->freeAll();
92 fGpu->markContextDirty();
93
bsalomon@google.com8fe72472011-03-30 21:26:44 +000094 this->setupDrawBuffer();
95}
96
97void GrContext::resetContext() {
98 fGpu->markContextDirty();
99}
100
101void GrContext::freeGpuResources() {
102 this->flush();
103 fTextureCache->removeAll();
104 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000105}
106
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000107////////////////////////////////////////////////////////////////////////////////
108
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000109enum {
110 kNPOTBit = 0x1,
111 kFilterBit = 0x2,
112 kKeylessBit = 0x4,
113};
114
115bool GrContext::finalizeTextureKey(GrTextureKey* key,
116 const GrSamplerState& sampler,
117 bool keyless) const {
118 uint32_t bits = 0;
119 uint16_t width = key->width();
120 uint16_t height = key->height();
121
122 if (!fGpu->npotTextureTileSupport()) {
123 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
124
125 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
126 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
127
128 if (tiled && !isPow2) {
129 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000130 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000131 bits |= kFilterBit;
132 }
133 }
134 }
135
136 if (keyless) {
137 bits |= kKeylessBit;
138 }
139 key->finalize(bits);
140 return 0 != bits;
141}
142
bsalomon@google.com27847de2011-02-22 20:59:41 +0000143GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
144 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000145 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000146 return fTextureCache->findAndLock(*key);
147}
148
149static void stretchImage(void* dst,
150 int dstW,
151 int dstH,
152 void* src,
153 int srcW,
154 int srcH,
155 int bpp) {
156 GrFixed dx = (srcW << 16) / dstW;
157 GrFixed dy = (srcH << 16) / dstH;
158
159 GrFixed y = dy >> 1;
160
161 int dstXLimit = dstW*bpp;
162 for (int j = 0; j < dstH; ++j) {
163 GrFixed x = dx >> 1;
164 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
165 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
166 for (int i = 0; i < dstXLimit; i += bpp) {
167 memcpy((uint8_t*) dstRow + i,
168 (uint8_t*) srcRow + (x>>16)*bpp,
169 bpp);
170 x += dx;
171 }
172 y += dy;
173 }
174}
175
176GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
177 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000178 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000179 void* srcData, size_t rowBytes) {
180 GrAssert(key->width() == desc.fWidth);
181 GrAssert(key->height() == desc.fHeight);
182
183#if GR_DUMP_TEXTURE_UPLOAD
184 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
185#endif
186
187 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000188 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000189 if (special) {
190 GrTextureEntry* clampEntry;
191 GrTextureKey clampKey(*key);
192 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
193
194 if (NULL == clampEntry) {
195 clampEntry = createAndLockTexture(&clampKey,
196 GrSamplerState::ClampNoFilter(),
197 desc, srcData, rowBytes);
198 GrAssert(NULL != clampEntry);
199 if (NULL == clampEntry) {
200 return NULL;
201 }
202 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000203 GrTextureDesc rtDesc = desc;
204 rtDesc.fFlags = rtDesc.fFlags |
205 kRenderTarget_GrTextureFlagBit |
206 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000207 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
208 fGpu->minRenderTargetWidth()));
209 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
210 fGpu->minRenderTargetHeight()));
211
212 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
213
214 if (NULL != texture) {
215 GrDrawTarget::AutoStateRestore asr(fGpu);
216 fGpu->setRenderTarget(texture->asRenderTarget());
217 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000218 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000219 fGpu->setViewMatrix(GrMatrix::I());
220 fGpu->setAlpha(0xff);
221 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
222 fGpu->disableState(GrDrawTarget::kDither_StateBit |
223 GrDrawTarget::kClip_StateBit |
224 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000225 GrSamplerState::Filter filter;
226 // if filtering is not desired then we want to ensure all
227 // texels in the resampled image are copies of texels from
228 // the original.
229 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
230 filter = GrSamplerState::kNearest_Filter;
231 } else {
232 filter = GrSamplerState::kBilinear_Filter;
233 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000234 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
235 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000236 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000237 fGpu->setSamplerState(0, stretchSampler);
238
239 static const GrVertexLayout layout =
240 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
241 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
242
243 if (arg.succeeded()) {
244 GrPoint* verts = (GrPoint*) arg.vertices();
245 verts[0].setIRectFan(0, 0,
246 texture->width(),
247 texture->height(),
248 2*sizeof(GrPoint));
249 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
250 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
251 0, 4);
252 entry = fTextureCache->createAndLock(*key, texture);
253 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000254 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000255 } else {
256 // TODO: Our CPU stretch doesn't filter. But we create separate
257 // stretched textures when the sampler state is either filtered or
258 // not. Either implement filtered stretch blit on CPU or just create
259 // one when FBO case fails.
260
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000261 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000262 // no longer need to clamp at min RT size.
263 rtDesc.fWidth = GrNextPow2(desc.fWidth);
264 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000265 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000266 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
267 rtDesc.fWidth *
268 rtDesc.fHeight);
269 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
270 srcData, desc.fWidth, desc.fHeight, bpp);
271
272 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
273
274 GrTexture* texture = fGpu->createTexture(rtDesc,
275 stretchedPixels.get(),
276 stretchedRowBytes);
277 GrAssert(NULL != texture);
278 entry = fTextureCache->createAndLock(*key, texture);
279 }
280 fTextureCache->unlock(clampEntry);
281
282 } else {
283 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
284 if (NULL != texture) {
285 entry = fTextureCache->createAndLock(*key, texture);
286 } else {
287 entry = NULL;
288 }
289 }
290 return entry;
291}
292
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000293GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000294 uint32_t p0 = desc.fFormat;
295 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
296 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000297 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
298
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000299 GrTextureEntry* entry = fTextureCache->findAndLock(key);
300 if (NULL == entry) {
301 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
302 if (NULL != texture) {
303 entry = fTextureCache->createAndLock(key, texture);
304 }
305 }
306 // If the caller gives us the same desc/sampler twice we don't want
307 // to return the same texture the second time (unless it was previously
308 // released). So we detach the entry from the cache and reattach at release.
309 if (NULL != entry) {
310 fTextureCache->detach(entry);
311 }
312 return entry;
313}
314
bsalomon@google.com27847de2011-02-22 20:59:41 +0000315void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000316 if (kKeylessBit & entry->key().getPrivateBits()) {
317 fTextureCache->reattachAndUnlock(entry);
318 } else {
319 fTextureCache->unlock(entry);
320 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000321}
322
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000323GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000324 void* srcData,
325 size_t rowBytes) {
326 return fGpu->createTexture(desc, srcData, rowBytes);
327}
328
329void GrContext::getTextureCacheLimits(int* maxTextures,
330 size_t* maxTextureBytes) const {
331 fTextureCache->getLimits(maxTextures, maxTextureBytes);
332}
333
334void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
335 fTextureCache->setLimits(maxTextures, maxTextureBytes);
336}
337
338int GrContext::getMaxTextureDimension() {
339 return fGpu->maxTextureDimension();
340}
341
342///////////////////////////////////////////////////////////////////////////////
343
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000344GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
345 // validate flags here so that GrGpu subclasses don't have to check
346 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
347 0 != desc.fRenderTargetFlags) {
348 return NULL;
349 }
350 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
351 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
352 return NULL;
353 }
354 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
355 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
356 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
357 return NULL;
358 }
359 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000360}
361
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000362GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,
363 int stencilBits,
364 bool isMultisampled,
365 int width, int height) {
366#if GR_DEBUG
367 GrPrintf("Using deprecated createPlatformRenderTarget API.");
368#endif
369 return fGpu->createPlatformRenderTarget(platformRenderTarget,
370 stencilBits, isMultisampled,
371 width, height);
372}
373
374GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
375#if GR_DEBUG
376 GrPrintf("Using deprecated createRenderTargetFrom3DApiState API.");
377#endif
378 return fGpu->createRenderTargetFrom3DApiState();
379}
380
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000381///////////////////////////////////////////////////////////////////////////////
382
bsalomon@google.com27847de2011-02-22 20:59:41 +0000383bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
384 int width, int height) {
385 if (!fGpu->supports8BitPalette()) {
386 return false;
387 }
388
389
390 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
391
392 if (!isPow2) {
393 if (!fGpu->npotTextureSupport()) {
394 return false;
395 }
396
397 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
398 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
399 if (tiled && !fGpu->npotTextureTileSupport()) {
400 return false;
401 }
402 }
403 return true;
404}
405
406////////////////////////////////////////////////////////////////////////////////
407
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000408const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
409
bsalomon@google.com27847de2011-02-22 20:59:41 +0000410void GrContext::setClip(const GrClip& clip) {
411 fGpu->setClip(clip);
412 fGpu->enableState(GrDrawTarget::kClip_StateBit);
413}
414
415void GrContext::setClip(const GrIRect& rect) {
416 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000417 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000418 fGpu->setClip(clip);
419}
420
421////////////////////////////////////////////////////////////////////////////////
422
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000423void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000424 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000425 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000426}
427
428void GrContext::drawPaint(const GrPaint& paint) {
429 // set rect to be big enough to fill the space, but not super-huge, so we
430 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000431 GrRect r;
432 r.setLTRB(0, 0,
433 GrIntToScalar(getRenderTarget()->width()),
434 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000435 GrMatrix inverse;
436 if (fGpu->getViewInverse(&inverse)) {
437 inverse.mapRect(&r);
438 } else {
439 GrPrintf("---- fGpu->getViewInverse failed\n");
440 }
441 this->drawRect(paint, r);
442}
443
bsalomon@google.com205d4602011-04-25 12:43:45 +0000444////////////////////////////////////////////////////////////////////////////////
445
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000446bool GrContext::doOffscreenAA(GrDrawTarget* target,
447 const GrPaint& paint,
448 bool isLines) const {
449#if !ENABLE_OFFSCREEN_AA
450 return false;
451#else
452 if (!paint.fAntiAlias) {
453 return false;
454 }
455 if (isLines && fGpu->supportsAALines()) {
456 return false;
457 }
458 if (target->getRenderTarget()->isMultisampled()) {
459 return false;
460 }
461 // we have to be sure that the blend equation is expressible
462 // as simple src / dst coeffecients when the source
463 // is already modulated by the coverage fraction.
464 // We could use dual-source blending to get the correct per-pixel
465 // dst coeffecient for the remaining cases.
466 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
467 kOne_BlendCoeff != paint.fDstBlendCoeff &&
468 kISA_BlendCoeff != paint.fDstBlendCoeff) {
469 return false;
470 }
471 return true;
472#endif
473}
474
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000475bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
476 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000477 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000478 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000479 GrAssert(ENABLE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000480
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000481 GrAssert(NULL == record->fEntry0);
482 GrAssert(NULL == record->fEntry1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000483
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000484 int boundW = boundRect.width();
485 int boundH = boundRect.height();
486 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000487
488 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000489 if (requireStencil) {
490 desc.fFlags = kRenderTarget_GrTextureFlagBit;
491 } else {
492 desc.fFlags = kRenderTarget_GrTextureFlagBit |
493 kNoStencil_GrTextureFlagBit;
494 }
495
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000496 desc.fFormat = kRGBA_8888_GrPixelConfig;
497
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000498 int scale;
499 // Using MSAA seems to be slower for some yet unknown reason.
500 if (false && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000501 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000502 scale = GR_Scalar1;
503 desc.fAALevel = kMed_GrAALevel;
504 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000505 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
506 OffscreenRecord::k4x4SinglePass_Downsample :
507 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000508 scale = 4;
509 desc.fAALevel = kNone_GrAALevel;
510 }
511
512 desc.fWidth = scale * size;
513 desc.fHeight = scale * size;
514
515 record->fEntry0 = this->lockKeylessTexture(desc);
516
517 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000518 return false;
519 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000520
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000521 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000522 desc.fWidth /= 2;
523 desc.fHeight /= 2;
524 record->fEntry1 = this->lockKeylessTexture(desc);
525 if (NULL == record->fEntry1) {
526 this->unlockTexture(record->fEntry0);
527 record->fEntry0 = NULL;
528 return false;
529 }
530 }
531
532 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
533 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000534
535 target->saveCurrentDrawState(&record->fSavedState);
536
537 GrPaint tempPaint;
538 tempPaint.reset();
539 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000540 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000541
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000542 GrMatrix transM;
543 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
544 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000545 GrMatrix scaleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000546 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000547 target->postConcatViewMatrix(scaleM);
548
549 // clip gets applied in second pass
550 target->disableState(GrDrawTarget::kClip_StateBit);
551
reed@google.com20efde72011-05-09 17:00:02 +0000552 GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000553 target->clear(&clear, 0x0);
554
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000555 return true;
556}
557
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000558void GrContext::offscreenAAPass2(GrDrawTarget* target,
559 const GrPaint& paint,
560 const GrIRect& boundRect,
561 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000562
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000563 GrAssert(NULL != record->fEntry0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000564
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000565 GrSamplerState::Filter filter;
566 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
567 filter = GrSamplerState::k4x4Downsample_Filter;
568 } else {
569 filter = GrSamplerState::kBilinear_Filter;
570 }
571
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000572 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000573 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000574 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000575
576 GrTexture* src = record->fEntry0->texture();
577 int scale;
578
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000579 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
580 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000581 scale = 2;
582 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
583
584 // Do 2x2 downsample from first to second
585 target->setTexture(kOffscreenStage, src);
586 target->setRenderTarget(dst);
587 target->setViewMatrix(GrMatrix::I());
588 sampleM.setScale(scale * GR_Scalar1 / src->width(),
589 scale * GR_Scalar1 / src->height());
590 sampler.setMatrix(sampleM);
591 target->setSamplerState(kOffscreenStage, sampler);
reed@google.com20efde72011-05-09 17:00:02 +0000592 GrRect rect = SkRect::MakeWH(scale * boundRect.width(),
593 scale * boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000594 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
595
596 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000597 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000598 scale = 1;
reed@google.com20efde72011-05-09 17:00:02 +0000599 GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000600 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000601 } else {
602 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
603 record->fDownsample);
604 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000605 }
606
607 // setup for draw back to main RT
608 target->restoreDrawState(record->fSavedState);
609 if (NULL != paint.getTexture()) {
610 GrMatrix invVM;
611 if (target->getViewInverse(&invVM)) {
612 target->preConcatSamplerMatrix(0, invVM);
613 }
614 }
615 target->setViewMatrix(GrMatrix::I());
616
617 target->setTexture(kOffscreenStage, src);
618 sampleM.setScale(scale * GR_Scalar1 / src->width(),
619 scale * GR_Scalar1 / src->height());
620 sampler.setMatrix(sampleM);
621 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
622 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000623 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000624
reed@google.com20efde72011-05-09 17:00:02 +0000625 GrRect dstRect;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000626 int stages = (1 << kOffscreenStage) | (NULL == paint.getTexture() ? 0 : 1);
reed@google.com20efde72011-05-09 17:00:02 +0000627 dstRect.set(boundRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000628 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000629
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000630 this->unlockTexture(record->fEntry0);
631 record->fEntry0 = NULL;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000632 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000633 this->unlockTexture(record->fEntry1);
634 record->fEntry1 = NULL;
635 }
636 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000637}
638
639////////////////////////////////////////////////////////////////////////////////
640
bsalomon@google.com27847de2011-02-22 20:59:41 +0000641/* create a triangle strip that strokes the specified triangle. There are 8
642 unique vertices, but we repreat the last 2 to close up. Alternatively we
643 could use an indices array, and then only send 8 verts, but not sure that
644 would be faster.
645 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000646static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000647 GrScalar width) {
648 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000649 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000650
651 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
652 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
653 verts[2].set(rect.fRight - rad, rect.fTop + rad);
654 verts[3].set(rect.fRight + rad, rect.fTop - rad);
655 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
656 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
657 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
658 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
659 verts[8] = verts[0];
660 verts[9] = verts[1];
661}
662
bsalomon@google.com205d4602011-04-25 12:43:45 +0000663static GrColor getColorForMesh(const GrPaint& paint) {
664 if (NULL == paint.getTexture()) {
665 return paint.fColor;
666 } else {
667 unsigned a = GrColorUnpackA(paint.fColor);
668 return GrColorPackRGBA(a, a, a, a);
669 }
670}
671
672static void setInsetFan(GrPoint* pts, size_t stride,
673 const GrRect& r, GrScalar dx, GrScalar dy) {
674 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
675}
676
677static const uint16_t gFillAARectIdx[] = {
678 0, 1, 5, 5, 4, 0,
679 1, 2, 6, 6, 5, 1,
680 2, 3, 7, 7, 6, 2,
681 3, 0, 4, 4, 7, 3,
682 4, 5, 6, 6, 7, 4,
683};
684
685int GrContext::aaFillRectIndexCount() const {
686 return GR_ARRAY_COUNT(gFillAARectIdx);
687}
688
689GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
690 if (NULL == fAAFillRectIndexBuffer) {
691 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
692 false);
693 GrAssert(NULL != fAAFillRectIndexBuffer);
694#if GR_DEBUG
695 bool updated =
696#endif
697 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
698 sizeof(gFillAARectIdx));
699 GR_DEBUGASSERT(updated);
700 }
701 return fAAFillRectIndexBuffer;
702}
703
704static const uint16_t gStrokeAARectIdx[] = {
705 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
706 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
707 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
708 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
709
710 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
711 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
712 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
713 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
714
715 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
716 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
717 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
718 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
719};
720
721int GrContext::aaStrokeRectIndexCount() const {
722 return GR_ARRAY_COUNT(gStrokeAARectIdx);
723}
724
725GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
726 if (NULL == fAAStrokeRectIndexBuffer) {
727 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
728 false);
729 GrAssert(NULL != fAAStrokeRectIndexBuffer);
730#if GR_DEBUG
731 bool updated =
732#endif
733 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
734 sizeof(gStrokeAARectIdx));
735 GR_DEBUGASSERT(updated);
736 }
737 return fAAStrokeRectIndexBuffer;
738}
739
740void GrContext::fillAARect(GrDrawTarget* target,
741 const GrPaint& paint,
742 const GrRect& devRect) {
743
744 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
745 if (NULL != paint.getTexture()) {
746 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
747 }
748
749 size_t vsize = GrDrawTarget::VertexSize(layout);
750
751 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
752
753 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
754
755 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
756 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
757
758 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
759 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
760
761 verts += sizeof(GrPoint);
762 for (int i = 0; i < 4; ++i) {
763 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
764 }
765
766 GrColor innerColor = getColorForMesh(paint);
767 verts += 4 * vsize;
768 for (int i = 0; i < 4; ++i) {
769 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
770 }
771
772 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
773
774 target->drawIndexed(kTriangles_PrimitiveType, 0,
775 0, 8, this->aaFillRectIndexCount());
776}
777
778void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
779 const GrRect& devRect, const GrVec& devStrokeSize) {
780 const GrScalar& dx = devStrokeSize.fX;
781 const GrScalar& dy = devStrokeSize.fY;
782 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
783 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
784
785 GrVertexLayout layout = GrDrawTarget::kColor_VertexLayoutBit;
786
787 if (NULL != paint.getTexture()) {
788 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
789 }
790
791 GrScalar spare;
792 {
793 GrScalar w = devRect.width() - dx;
794 GrScalar h = devRect.height() - dy;
795 spare = GrMin(w, h);
796 }
797
798 if (spare <= 0) {
799 GrRect r(devRect);
800 r.inset(-rx, -ry);
801 fillAARect(target, paint, r);
802 return;
803 }
804
805 size_t vsize = GrDrawTarget::VertexSize(layout);
806
807 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
808
809 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
810
811 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
812 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
813 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
814 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
815
816 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
817 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
818 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
819 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
820
821 verts += sizeof(GrPoint);
822 for (int i = 0; i < 4; ++i) {
823 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
824 }
825
826 GrColor innerColor = getColorForMesh(paint);
827 verts += 4 * vsize;
828 for (int i = 0; i < 8; ++i) {
829 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
830 }
831
832 verts += 8 * vsize;
833 for (int i = 0; i < 8; ++i) {
834 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
835 }
836
837 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
838 target->drawIndexed(kTriangles_PrimitiveType,
839 0, 0, 16, aaStrokeRectIndexCount());
840}
841
reed@google.com20efde72011-05-09 17:00:02 +0000842/**
843 * Returns true if the rects edges are integer-aligned.
844 */
845static bool isIRect(const GrRect& r) {
846 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
847 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
848}
849
bsalomon@google.com205d4602011-04-25 12:43:45 +0000850static bool apply_aa_to_rect(GrDrawTarget* target,
851 GrGpu* gpu,
852 const GrPaint& paint,
853 const GrRect& rect,
854 GrScalar width,
855 const GrMatrix* matrix,
856 GrMatrix* combinedMatrix,
857 GrRect* devRect) {
858 // we use a simple alpha ramp to do aa on axis-aligned rects
859 // do AA with alpha ramp if the caller requested AA, the rect
860 // will be axis-aligned,the render target is not
861 // multisampled, and the rect won't land on integer coords.
862
863 if (!paint.fAntiAlias) {
864 return false;
865 }
866
867 if (target->getRenderTarget()->isMultisampled()) {
868 return false;
869 }
870
871 if (0 == width && gpu->supportsAALines()) {
872 return false;
873 }
874
875 if (!target->getViewMatrix().preservesAxisAlignment()) {
876 return false;
877 }
878
879 if (NULL != matrix &&
880 !matrix->preservesAxisAlignment()) {
881 return false;
882 }
883
884 *combinedMatrix = target->getViewMatrix();
885 if (NULL != matrix) {
886 combinedMatrix->preConcat(*matrix);
887 GrAssert(combinedMatrix->preservesAxisAlignment());
888 }
889
890 combinedMatrix->mapRect(devRect, rect);
891 devRect->sort();
892
893 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000894 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000895 } else {
896 return true;
897 }
898}
899
bsalomon@google.com27847de2011-02-22 20:59:41 +0000900void GrContext::drawRect(const GrPaint& paint,
901 const GrRect& rect,
902 GrScalar width,
903 const GrMatrix* matrix) {
904
905 bool textured = NULL != paint.getTexture();
906
907 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
908
bsalomon@google.com205d4602011-04-25 12:43:45 +0000909 GrRect devRect = rect;
910 GrMatrix combinedMatrix;
911 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
912 &combinedMatrix, &devRect);
913
914 if (doAA) {
915 GrDrawTarget::AutoViewMatrixRestore avm(target);
916 if (textured) {
917 GrMatrix inv;
918 if (combinedMatrix.invert(&inv)) {
919 target->preConcatSamplerMatrix(0, inv);
920 }
921 }
922 target->setViewMatrix(GrMatrix::I());
923 if (width >= 0) {
924 GrVec strokeSize;;
925 if (width > 0) {
926 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000927 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000928 strokeSize.setAbs(strokeSize);
929 } else {
930 strokeSize.set(GR_Scalar1, GR_Scalar1);
931 }
932 strokeAARect(target, paint, devRect, strokeSize);
933 } else {
934 fillAARect(target, paint, devRect);
935 }
936 return;
937 }
938
bsalomon@google.com27847de2011-02-22 20:59:41 +0000939 if (width >= 0) {
940 // TODO: consider making static vertex buffers for these cases.
941 // Hairline could be done by just adding closing vertex to
942 // unitSquareVertexBuffer()
bsalomon@google.com205d4602011-04-25 12:43:45 +0000943 GrVertexLayout layout = textured ?
944 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
945 0;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000946 static const int worstCaseVertCount = 10;
947 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
948
949 if (!geo.succeeded()) {
950 return;
951 }
952
953 GrPrimitiveType primType;
954 int vertCount;
955 GrPoint* vertex = geo.positions();
956
957 if (width > 0) {
958 vertCount = 10;
959 primType = kTriangleStrip_PrimitiveType;
960 setStrokeRectStrip(vertex, rect, width);
961 } else {
962 // hairline
963 vertCount = 5;
964 primType = kLineStrip_PrimitiveType;
965 vertex[0].set(rect.fLeft, rect.fTop);
966 vertex[1].set(rect.fRight, rect.fTop);
967 vertex[2].set(rect.fRight, rect.fBottom);
968 vertex[3].set(rect.fLeft, rect.fBottom);
969 vertex[4].set(rect.fLeft, rect.fTop);
970 }
971
972 GrDrawTarget::AutoViewMatrixRestore avmr;
973 if (NULL != matrix) {
974 avmr.set(target);
975 target->preConcatViewMatrix(*matrix);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000976 if (textured) {
977 target->preConcatSamplerMatrix(0, *matrix);
978 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000979 }
980
981 target->drawNonIndexed(primType, 0, vertCount);
982 } else {
983 #if GR_STATIC_RECT_VB
984 GrVertexLayout layout = (textured) ?
985 GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) :
986 0;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +0000987 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000988 fGpu->getUnitSquareVertexBuffer());
989 GrDrawTarget::AutoViewMatrixRestore avmr(target);
990 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000991 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000992 0, rect.height(), rect.fTop,
993 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000994
995 if (NULL != matrix) {
996 m.postConcat(*matrix);
997 }
998
999 target->preConcatViewMatrix(m);
1000
1001 if (textured) {
1002 target->preConcatSamplerMatrix(0, m);
1003 }
1004 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1005 #else
1006 target->drawSimpleRect(rect, matrix, textured ? 1 : 0);
1007 #endif
1008 }
1009}
1010
1011void GrContext::drawRectToRect(const GrPaint& paint,
1012 const GrRect& dstRect,
1013 const GrRect& srcRect,
1014 const GrMatrix* dstMatrix,
1015 const GrMatrix* srcMatrix) {
1016
1017 if (NULL == paint.getTexture()) {
1018 drawRect(paint, dstRect, -1, dstMatrix);
1019 return;
1020 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001021
bsalomon@google.com27847de2011-02-22 20:59:41 +00001022 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1023
1024#if GR_STATIC_RECT_VB
1025 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1026
1027 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1028 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1029
1030 GrMatrix m;
1031
1032 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1033 0, dstRect.height(), dstRect.fTop,
1034 0, 0, GrMatrix::I()[8]);
1035 if (NULL != dstMatrix) {
1036 m.postConcat(*dstMatrix);
1037 }
1038 target->preConcatViewMatrix(m);
1039
1040 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1041 0, srcRect.height(), srcRect.fTop,
1042 0, 0, GrMatrix::I()[8]);
1043 if (NULL != srcMatrix) {
1044 m.postConcat(*srcMatrix);
1045 }
1046 target->preConcatSamplerMatrix(0, m);
1047
1048 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1049 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1050#else
1051
1052 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001053#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001054 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001055#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001056 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1057#endif
1058
1059 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1060 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1061 srcRects[0] = &srcRect;
1062 srcMatrices[0] = srcMatrix;
1063
1064 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1065#endif
1066}
1067
1068void GrContext::drawVertices(const GrPaint& paint,
1069 GrPrimitiveType primitiveType,
1070 int vertexCount,
1071 const GrPoint positions[],
1072 const GrPoint texCoords[],
1073 const GrColor colors[],
1074 const uint16_t indices[],
1075 int indexCount) {
1076 GrVertexLayout layout = 0;
1077 int vertexSize = sizeof(GrPoint);
1078
1079 GrDrawTarget::AutoReleaseGeometry geo;
1080
1081 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1082
1083 if (NULL != paint.getTexture()) {
1084 if (NULL == texCoords) {
1085 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1086 } else {
1087 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
1088 vertexSize += sizeof(GrPoint);
1089 }
1090 }
1091
1092 if (NULL != colors) {
1093 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1094 vertexSize += sizeof(GrColor);
1095 }
1096
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001097 bool doAA = false;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001098 OffscreenRecord record;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001099 GrIRect bounds;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001100
bsalomon@google.com27847de2011-02-22 20:59:41 +00001101 if (sizeof(GrPoint) != vertexSize) {
1102 if (!geo.set(target, layout, vertexCount, 0)) {
1103 GrPrintf("Failed to get space for vertices!");
1104 return;
1105 }
1106 int texOffsets[GrDrawTarget::kMaxTexCoords];
1107 int colorOffset;
1108 int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1109 texOffsets,
1110 &colorOffset);
1111 void* curVertex = geo.vertices();
1112
1113 for (int i = 0; i < vertexCount; ++i) {
1114 *((GrPoint*)curVertex) = positions[i];
1115
1116 if (texOffsets[0] > 0) {
1117 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1118 }
1119 if (colorOffset > 0) {
1120 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1121 }
1122 curVertex = (void*)((intptr_t)curVertex + vsize);
1123 }
1124 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001125 // we don't do offscreen AA when we have per-vertex tex coords or colors
1126 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1127 GrRect b;
1128 b.setBounds(positions, vertexCount);
1129 target->getViewMatrix().mapRect(&b);
1130 b.roundOut(&bounds);
1131
1132 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1133 doAA = true;
1134 }
1135 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001136 target->setVertexSourceToArray(layout, positions, vertexCount);
1137 }
1138
1139 if (NULL != indices) {
1140 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001141 }
1142
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001143 if (NULL != indices) {
1144 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001145 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001146 target->drawNonIndexed(primitiveType, 0, vertexCount);
1147 }
1148
1149 if (doAA) {
1150 this->offscreenAAPass2(target, paint, bounds, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001151 }
1152}
1153
1154
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001155///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001156
reed@google.com07f3ee12011-05-16 17:21:57 +00001157void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1158 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159
bsalomon@google.com27847de2011-02-22 20:59:41 +00001160 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001161 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001162
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001163 if (!IsFillInverted(fill) && // will be relaxed soon
1164 !pr->supportsAA(target, path, fill) &&
1165 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001166
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001167 OffscreenRecord record;
1168 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001169
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001170 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001171 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1172 target->getRenderTarget()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001173 if (target->getClip().hasConservativeBounds()) {
1174 GrIRect clipIBounds;
1175 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001176 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001177 return;
1178 }
1179 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001180 GrRect pathBounds = path.getBounds();
1181 if (!pathBounds.isEmpty()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001182 GrIRect pathIBounds;
1183 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1184 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001185 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001186 return;
1187 }
1188 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001189
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001190 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1191 pr->drawPath(target, 0, path, fill, translate);
1192 this->offscreenAAPass2(target, paint, bound, &record);
1193 return;
1194 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001195 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196 GrDrawTarget::StageBitfield enabledStages = 0;
1197 if (NULL != paint.getTexture()) {
1198 enabledStages |= 1;
1199 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001200
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001201 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001202}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001203
bsalomon@google.com27847de2011-02-22 20:59:41 +00001204////////////////////////////////////////////////////////////////////////////////
1205
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001206void GrContext::flush(int flagsBitfield) {
1207 if (kDiscard_FlushBit & flagsBitfield) {
1208 fDrawBuffer->reset();
1209 } else {
1210 flushDrawBuffer();
1211 }
1212
1213 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001214 fGpu->forceRenderTargetFlush();
1215 }
1216}
1217
1218void GrContext::flushText() {
1219 if (kText_DrawCategory == fLastDrawCategory) {
1220 flushDrawBuffer();
1221 }
1222}
1223
1224void GrContext::flushDrawBuffer() {
1225#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1226 fDrawBuffer->playback(fGpu);
1227 fDrawBuffer->reset();
1228#endif
1229}
1230
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001231bool GrContext::readTexturePixels(GrTexture* texture,
1232 int left, int top, int width, int height,
1233 GrPixelConfig config, void* buffer) {
1234
1235 // TODO: code read pixels for textures that aren't rendertargets
1236
1237 this->flush();
1238 GrRenderTarget* target = texture->asRenderTarget();
1239 if (NULL != target) {
1240 return fGpu->readPixels(target,
1241 left, top, width, height,
1242 config, buffer);
1243 } else {
1244 return false;
1245 }
1246}
1247
1248bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1249 int left, int top, int width, int height,
1250 GrPixelConfig config, void* buffer) {
1251 uint32_t flushFlags = 0;
1252 if (NULL == target) {
1253 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1254 }
1255
1256 this->flush(flushFlags);
1257 return fGpu->readPixels(target,
1258 left, top, width, height,
1259 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001260}
1261
1262void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001263 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001264 size_t stride) {
1265
1266 // TODO: when underlying api has a direct way to do this we should use it
1267 // (e.g. glDrawPixels on desktop GL).
1268
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001269 const GrTextureDesc desc = {
1270 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001271 };
1272 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1273 if (NULL == texture) {
1274 return;
1275 }
1276
1277 this->flush(true);
1278
1279 GrAutoUnref aur(texture);
1280 GrDrawTarget::AutoStateRestore asr(fGpu);
1281
1282 GrMatrix matrix;
1283 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1284 fGpu->setViewMatrix(matrix);
1285
1286 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1287 fGpu->setAlpha(0xFF);
1288 fGpu->setBlendFunc(kOne_BlendCoeff,
1289 kZero_BlendCoeff);
1290 fGpu->setTexture(0, texture);
1291
1292 GrSamplerState sampler;
1293 sampler.setClampNoFilter();
1294 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1295 sampler.setMatrix(matrix);
1296 fGpu->setSamplerState(0, sampler);
1297
1298 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1299 static const int VCOUNT = 4;
1300
1301 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1302 if (!geo.succeeded()) {
1303 return;
1304 }
1305 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1306 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1307}
1308////////////////////////////////////////////////////////////////////////////////
1309
1310void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
1311 target->setTexture(0, paint.getTexture());
1312 target->setSamplerState(0, paint.fSampler);
1313 target->setColor(paint.fColor);
1314
1315 if (paint.fDither) {
1316 target->enableState(GrDrawTarget::kDither_StateBit);
1317 } else {
1318 target->disableState(GrDrawTarget::kDither_StateBit);
1319 }
1320 if (paint.fAntiAlias) {
1321 target->enableState(GrDrawTarget::kAntialias_StateBit);
1322 } else {
1323 target->disableState(GrDrawTarget::kAntialias_StateBit);
1324 }
1325 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001326 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327}
1328
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001329GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001330 DrawCategory category) {
1331 if (category != fLastDrawCategory) {
1332 flushDrawBuffer();
1333 fLastDrawCategory = category;
1334 }
1335 SetPaint(paint, fGpu);
1336 GrDrawTarget* target = fGpu;
1337 switch (category) {
1338 case kText_DrawCategory:
1339#if DEFER_TEXT_RENDERING
1340 target = fDrawBuffer;
1341 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1342#else
1343 target = fGpu;
1344#endif
1345 break;
1346 case kUnbuffered_DrawCategory:
1347 target = fGpu;
1348 break;
1349 case kBuffered_DrawCategory:
1350 target = fDrawBuffer;
1351 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1352 break;
1353 }
1354 return target;
1355}
1356
1357////////////////////////////////////////////////////////////////////////////////
1358
bsalomon@google.com27847de2011-02-22 20:59:41 +00001359void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001360 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001361 fGpu->setRenderTarget(target);
1362}
1363
1364GrRenderTarget* GrContext::getRenderTarget() {
1365 return fGpu->getRenderTarget();
1366}
1367
1368const GrRenderTarget* GrContext::getRenderTarget() const {
1369 return fGpu->getRenderTarget();
1370}
1371
1372const GrMatrix& GrContext::getMatrix() const {
1373 return fGpu->getViewMatrix();
1374}
1375
1376void GrContext::setMatrix(const GrMatrix& m) {
1377 fGpu->setViewMatrix(m);
1378}
1379
1380void GrContext::concatMatrix(const GrMatrix& m) const {
1381 fGpu->preConcatViewMatrix(m);
1382}
1383
1384static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1385 intptr_t mask = 1 << shift;
1386 if (pred) {
1387 bits |= mask;
1388 } else {
1389 bits &= ~mask;
1390 }
1391 return bits;
1392}
1393
1394void GrContext::resetStats() {
1395 fGpu->resetStats();
1396}
1397
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001398const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001399 return fGpu->getStats();
1400}
1401
1402void GrContext::printStats() const {
1403 fGpu->printStats();
1404}
1405
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001406GrContext::GrContext(GrGpu* gpu) :
1407 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1408 gpu->supportsStencilWrapOps()) {
1409
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410 fGpu = gpu;
1411 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001412 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001413
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001414 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1415 fGpu->setClipPathRenderer(fCustomPathRenderer);
1416
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1418 MAX_TEXTURE_CACHE_BYTES);
1419 fFontCache = new GrFontCache(fGpu);
1420
1421 fLastDrawCategory = kUnbuffered_DrawCategory;
1422
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001423 fDrawBuffer = NULL;
1424 fDrawBufferVBAllocPool = NULL;
1425 fDrawBufferIBAllocPool = NULL;
1426
bsalomon@google.com205d4602011-04-25 12:43:45 +00001427 fAAFillRectIndexBuffer = NULL;
1428 fAAStrokeRectIndexBuffer = NULL;
1429
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001430 this->setupDrawBuffer();
1431}
1432
1433void GrContext::setupDrawBuffer() {
1434
1435 GrAssert(NULL == fDrawBuffer);
1436 GrAssert(NULL == fDrawBufferVBAllocPool);
1437 GrAssert(NULL == fDrawBufferIBAllocPool);
1438
bsalomon@google.com27847de2011-02-22 20:59:41 +00001439#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001440 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001441 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001442 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1443 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001444 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001445 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001446 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001447 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1448
1449 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1450 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001451#endif
1452
1453#if BATCH_RECT_TO_RECT
1454 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1455#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001456}
1457
bsalomon@google.com27847de2011-02-22 20:59:41 +00001458GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1459 GrDrawTarget* target;
1460#if DEFER_TEXT_RENDERING
1461 target = prepareToDraw(paint, kText_DrawCategory);
1462#else
1463 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1464#endif
1465 SetPaint(paint, target);
1466 return target;
1467}
1468
1469const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1470 return fGpu->getQuadIndexBuffer();
1471}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001472
1473GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001474 const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001475 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001476 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001477 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1478 return fCustomPathRenderer;
1479 } else {
1480 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1481 return &fDefaultPathRenderer;
1482 }
1483}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001484