blob: af777c1bf7c6112df574c50fc4ffcdd7f35eb7fd [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.com26c2d0a2011-05-17 20:15:30 +0000109int GrContext::PaintStageVertexLayoutBits(
110 const GrPaint& paint,
111 const bool hasTexCoords[GrPaint::kTotalStages]) {
112 int stageMask = paint.getActiveStageMask();
113 int layout = 0;
114 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
115 if ((1 << i) & stageMask) {
116 if (NULL != hasTexCoords && hasTexCoords[i]) {
117 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
118 } else {
119 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
120 }
121 }
122 }
123 return layout;
124}
125
126
127////////////////////////////////////////////////////////////////////////////////
128
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000129enum {
130 kNPOTBit = 0x1,
131 kFilterBit = 0x2,
132 kKeylessBit = 0x4,
133};
134
135bool GrContext::finalizeTextureKey(GrTextureKey* key,
136 const GrSamplerState& sampler,
137 bool keyless) const {
138 uint32_t bits = 0;
139 uint16_t width = key->width();
140 uint16_t height = key->height();
141
142 if (!fGpu->npotTextureTileSupport()) {
143 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
144
145 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
146 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
147
148 if (tiled && !isPow2) {
149 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000150 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000151 bits |= kFilterBit;
152 }
153 }
154 }
155
156 if (keyless) {
157 bits |= kKeylessBit;
158 }
159 key->finalize(bits);
160 return 0 != bits;
161}
162
bsalomon@google.com27847de2011-02-22 20:59:41 +0000163GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
164 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000165 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000166 return fTextureCache->findAndLock(*key);
167}
168
169static void stretchImage(void* dst,
170 int dstW,
171 int dstH,
172 void* src,
173 int srcW,
174 int srcH,
175 int bpp) {
176 GrFixed dx = (srcW << 16) / dstW;
177 GrFixed dy = (srcH << 16) / dstH;
178
179 GrFixed y = dy >> 1;
180
181 int dstXLimit = dstW*bpp;
182 for (int j = 0; j < dstH; ++j) {
183 GrFixed x = dx >> 1;
184 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
185 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
186 for (int i = 0; i < dstXLimit; i += bpp) {
187 memcpy((uint8_t*) dstRow + i,
188 (uint8_t*) srcRow + (x>>16)*bpp,
189 bpp);
190 x += dx;
191 }
192 y += dy;
193 }
194}
195
196GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
197 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000198 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000199 void* srcData, size_t rowBytes) {
200 GrAssert(key->width() == desc.fWidth);
201 GrAssert(key->height() == desc.fHeight);
202
203#if GR_DUMP_TEXTURE_UPLOAD
204 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
205#endif
206
207 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000208 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000209 if (special) {
210 GrTextureEntry* clampEntry;
211 GrTextureKey clampKey(*key);
212 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
213
214 if (NULL == clampEntry) {
215 clampEntry = createAndLockTexture(&clampKey,
216 GrSamplerState::ClampNoFilter(),
217 desc, srcData, rowBytes);
218 GrAssert(NULL != clampEntry);
219 if (NULL == clampEntry) {
220 return NULL;
221 }
222 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000223 GrTextureDesc rtDesc = desc;
224 rtDesc.fFlags = rtDesc.fFlags |
225 kRenderTarget_GrTextureFlagBit |
226 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000227 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
228 fGpu->minRenderTargetWidth()));
229 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
230 fGpu->minRenderTargetHeight()));
231
232 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
233
234 if (NULL != texture) {
235 GrDrawTarget::AutoStateRestore asr(fGpu);
236 fGpu->setRenderTarget(texture->asRenderTarget());
237 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000238 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000239 fGpu->setViewMatrix(GrMatrix::I());
240 fGpu->setAlpha(0xff);
241 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
242 fGpu->disableState(GrDrawTarget::kDither_StateBit |
243 GrDrawTarget::kClip_StateBit |
244 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000245 GrSamplerState::Filter filter;
246 // if filtering is not desired then we want to ensure all
247 // texels in the resampled image are copies of texels from
248 // the original.
249 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
250 filter = GrSamplerState::kNearest_Filter;
251 } else {
252 filter = GrSamplerState::kBilinear_Filter;
253 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000254 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
255 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000256 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000257 fGpu->setSamplerState(0, stretchSampler);
258
259 static const GrVertexLayout layout =
260 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
261 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
262
263 if (arg.succeeded()) {
264 GrPoint* verts = (GrPoint*) arg.vertices();
265 verts[0].setIRectFan(0, 0,
266 texture->width(),
267 texture->height(),
268 2*sizeof(GrPoint));
269 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
270 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
271 0, 4);
272 entry = fTextureCache->createAndLock(*key, texture);
273 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000274 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000275 } else {
276 // TODO: Our CPU stretch doesn't filter. But we create separate
277 // stretched textures when the sampler state is either filtered or
278 // not. Either implement filtered stretch blit on CPU or just create
279 // one when FBO case fails.
280
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000281 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000282 // no longer need to clamp at min RT size.
283 rtDesc.fWidth = GrNextPow2(desc.fWidth);
284 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000285 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000286 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
287 rtDesc.fWidth *
288 rtDesc.fHeight);
289 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
290 srcData, desc.fWidth, desc.fHeight, bpp);
291
292 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
293
294 GrTexture* texture = fGpu->createTexture(rtDesc,
295 stretchedPixels.get(),
296 stretchedRowBytes);
297 GrAssert(NULL != texture);
298 entry = fTextureCache->createAndLock(*key, texture);
299 }
300 fTextureCache->unlock(clampEntry);
301
302 } else {
303 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
304 if (NULL != texture) {
305 entry = fTextureCache->createAndLock(*key, texture);
306 } else {
307 entry = NULL;
308 }
309 }
310 return entry;
311}
312
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000313GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000314 uint32_t p0 = desc.fFormat;
315 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
316 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000317 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
318
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000319 GrTextureEntry* entry = fTextureCache->findAndLock(key);
320 if (NULL == entry) {
321 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
322 if (NULL != texture) {
323 entry = fTextureCache->createAndLock(key, texture);
324 }
325 }
326 // If the caller gives us the same desc/sampler twice we don't want
327 // to return the same texture the second time (unless it was previously
328 // released). So we detach the entry from the cache and reattach at release.
329 if (NULL != entry) {
330 fTextureCache->detach(entry);
331 }
332 return entry;
333}
334
bsalomon@google.com27847de2011-02-22 20:59:41 +0000335void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000336 if (kKeylessBit & entry->key().getPrivateBits()) {
337 fTextureCache->reattachAndUnlock(entry);
338 } else {
339 fTextureCache->unlock(entry);
340 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000341}
342
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000343GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000344 void* srcData,
345 size_t rowBytes) {
346 return fGpu->createTexture(desc, srcData, rowBytes);
347}
348
349void GrContext::getTextureCacheLimits(int* maxTextures,
350 size_t* maxTextureBytes) const {
351 fTextureCache->getLimits(maxTextures, maxTextureBytes);
352}
353
354void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
355 fTextureCache->setLimits(maxTextures, maxTextureBytes);
356}
357
358int GrContext::getMaxTextureDimension() {
359 return fGpu->maxTextureDimension();
360}
361
362///////////////////////////////////////////////////////////////////////////////
363
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000364GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
365 // validate flags here so that GrGpu subclasses don't have to check
366 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
367 0 != desc.fRenderTargetFlags) {
368 return NULL;
369 }
370 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
371 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
372 return NULL;
373 }
374 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
375 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
376 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
377 return NULL;
378 }
379 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000380}
381
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000382GrRenderTarget* GrContext::createPlatformRenderTarget(intptr_t platformRenderTarget,
383 int stencilBits,
384 bool isMultisampled,
385 int width, int height) {
386#if GR_DEBUG
387 GrPrintf("Using deprecated createPlatformRenderTarget API.");
388#endif
389 return fGpu->createPlatformRenderTarget(platformRenderTarget,
390 stencilBits, isMultisampled,
391 width, height);
392}
393
394GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
395#if GR_DEBUG
396 GrPrintf("Using deprecated createRenderTargetFrom3DApiState API.");
397#endif
398 return fGpu->createRenderTargetFrom3DApiState();
399}
400
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000401///////////////////////////////////////////////////////////////////////////////
402
bsalomon@google.com27847de2011-02-22 20:59:41 +0000403bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
404 int width, int height) {
405 if (!fGpu->supports8BitPalette()) {
406 return false;
407 }
408
409
410 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
411
412 if (!isPow2) {
413 if (!fGpu->npotTextureSupport()) {
414 return false;
415 }
416
417 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
418 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
419 if (tiled && !fGpu->npotTextureTileSupport()) {
420 return false;
421 }
422 }
423 return true;
424}
425
426////////////////////////////////////////////////////////////////////////////////
427
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000428const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
429
bsalomon@google.com27847de2011-02-22 20:59:41 +0000430void GrContext::setClip(const GrClip& clip) {
431 fGpu->setClip(clip);
432 fGpu->enableState(GrDrawTarget::kClip_StateBit);
433}
434
435void GrContext::setClip(const GrIRect& rect) {
436 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000437 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000438 fGpu->setClip(clip);
439}
440
441////////////////////////////////////////////////////////////////////////////////
442
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000443void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000444 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000445 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000446}
447
448void GrContext::drawPaint(const GrPaint& paint) {
449 // set rect to be big enough to fill the space, but not super-huge, so we
450 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000451 GrRect r;
452 r.setLTRB(0, 0,
453 GrIntToScalar(getRenderTarget()->width()),
454 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000455 GrMatrix inverse;
456 if (fGpu->getViewInverse(&inverse)) {
457 inverse.mapRect(&r);
458 } else {
459 GrPrintf("---- fGpu->getViewInverse failed\n");
460 }
461 this->drawRect(paint, r);
462}
463
bsalomon@google.com205d4602011-04-25 12:43:45 +0000464////////////////////////////////////////////////////////////////////////////////
465
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000466bool GrContext::doOffscreenAA(GrDrawTarget* target,
467 const GrPaint& paint,
468 bool isLines) const {
469#if !ENABLE_OFFSCREEN_AA
470 return false;
471#else
472 if (!paint.fAntiAlias) {
473 return false;
474 }
475 if (isLines && fGpu->supportsAALines()) {
476 return false;
477 }
478 if (target->getRenderTarget()->isMultisampled()) {
479 return false;
480 }
481 // we have to be sure that the blend equation is expressible
482 // as simple src / dst coeffecients when the source
483 // is already modulated by the coverage fraction.
484 // We could use dual-source blending to get the correct per-pixel
485 // dst coeffecient for the remaining cases.
486 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
487 kOne_BlendCoeff != paint.fDstBlendCoeff &&
488 kISA_BlendCoeff != paint.fDstBlendCoeff) {
489 return false;
490 }
491 return true;
492#endif
493}
494
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000495bool GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
496 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000497 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000498 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000499 GrAssert(ENABLE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000500
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000501 GrAssert(NULL == record->fEntry0);
502 GrAssert(NULL == record->fEntry1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000503
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000504 int boundW = boundRect.width();
505 int boundH = boundRect.height();
506 int size = GrMax(64, (int)GrNextPow2(GrMax(boundW, boundH)));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000507
508 GrTextureDesc desc;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000509 if (requireStencil) {
510 desc.fFlags = kRenderTarget_GrTextureFlagBit;
511 } else {
512 desc.fFlags = kRenderTarget_GrTextureFlagBit |
513 kNoStencil_GrTextureFlagBit;
514 }
515
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000516 desc.fFormat = kRGBA_8888_GrPixelConfig;
517
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000518 int scale;
519 // Using MSAA seems to be slower for some yet unknown reason.
520 if (false && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000521 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000522 scale = GR_Scalar1;
523 desc.fAALevel = kMed_GrAALevel;
524 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000525 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
526 OffscreenRecord::k4x4SinglePass_Downsample :
527 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000528 scale = 4;
529 desc.fAALevel = kNone_GrAALevel;
530 }
531
532 desc.fWidth = scale * size;
533 desc.fHeight = scale * size;
534
535 record->fEntry0 = this->lockKeylessTexture(desc);
536
537 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000538 return false;
539 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000540
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000541 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000542 desc.fWidth /= 2;
543 desc.fHeight /= 2;
544 record->fEntry1 = this->lockKeylessTexture(desc);
545 if (NULL == record->fEntry1) {
546 this->unlockTexture(record->fEntry0);
547 record->fEntry0 = NULL;
548 return false;
549 }
550 }
551
552 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
553 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000554
555 target->saveCurrentDrawState(&record->fSavedState);
556
557 GrPaint tempPaint;
558 tempPaint.reset();
559 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000560 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000561
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000562 GrMatrix transM;
563 transM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
564 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000565 GrMatrix scaleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000566 scaleM.setScale(scale * GR_Scalar1, scale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000567 target->postConcatViewMatrix(scaleM);
568
569 // clip gets applied in second pass
570 target->disableState(GrDrawTarget::kClip_StateBit);
571
reed@google.com20efde72011-05-09 17:00:02 +0000572 GrIRect clear = SkIRect::MakeWH(scale * boundW, scale * boundH);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000573 target->clear(&clear, 0x0);
574
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000575 return true;
576}
577
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000578void GrContext::offscreenAAPass2(GrDrawTarget* target,
579 const GrPaint& paint,
580 const GrIRect& boundRect,
581 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000582
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000583 GrAssert(NULL != record->fEntry0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000584
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000585 GrSamplerState::Filter filter;
586 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
587 filter = GrSamplerState::k4x4Downsample_Filter;
588 } else {
589 filter = GrSamplerState::kBilinear_Filter;
590 }
591
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000592 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000593 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000594 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000595
596 GrTexture* src = record->fEntry0->texture();
597 int scale;
598
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000599 enum {
600 kOffscreenStage = GrPaint::kTotalStages,
601 };
602
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000603 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
604 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000605 scale = 2;
606 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
607
608 // Do 2x2 downsample from first to second
609 target->setTexture(kOffscreenStage, src);
610 target->setRenderTarget(dst);
611 target->setViewMatrix(GrMatrix::I());
612 sampleM.setScale(scale * GR_Scalar1 / src->width(),
613 scale * GR_Scalar1 / src->height());
614 sampler.setMatrix(sampleM);
615 target->setSamplerState(kOffscreenStage, sampler);
reed@google.com20efde72011-05-09 17:00:02 +0000616 GrRect rect = SkRect::MakeWH(scale * boundRect.width(),
617 scale * boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000618 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
619
620 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000621 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000622 scale = 1;
reed@google.com20efde72011-05-09 17:00:02 +0000623 GrIRect rect = SkIRect::MakeWH(boundRect.width(), boundRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000624 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000625 } else {
626 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
627 record->fDownsample);
628 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000629 }
630
631 // setup for draw back to main RT
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000632 int stageMask = paint.getActiveStageMask();
633
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000634 target->restoreDrawState(record->fSavedState);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000635
636 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000637 GrMatrix invVM;
638 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000639 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000640 }
641 }
642 target->setViewMatrix(GrMatrix::I());
643
644 target->setTexture(kOffscreenStage, src);
645 sampleM.setScale(scale * GR_Scalar1 / src->width(),
646 scale * GR_Scalar1 / src->height());
647 sampler.setMatrix(sampleM);
648 sampleM.setTranslate(-boundRect.fLeft, -boundRect.fTop);
649 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000650 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000651
reed@google.com20efde72011-05-09 17:00:02 +0000652 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000653 int stages = (1 << kOffscreenStage) | stageMask;
reed@google.com20efde72011-05-09 17:00:02 +0000654 dstRect.set(boundRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000655 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000656
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000657 this->unlockTexture(record->fEntry0);
658 record->fEntry0 = NULL;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000659 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000660 this->unlockTexture(record->fEntry1);
661 record->fEntry1 = NULL;
662 }
663 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000664}
665
666////////////////////////////////////////////////////////////////////////////////
667
bsalomon@google.com27847de2011-02-22 20:59:41 +0000668/* create a triangle strip that strokes the specified triangle. There are 8
669 unique vertices, but we repreat the last 2 to close up. Alternatively we
670 could use an indices array, and then only send 8 verts, but not sure that
671 would be faster.
672 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000673static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000674 GrScalar width) {
675 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000676 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000677
678 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
679 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
680 verts[2].set(rect.fRight - rad, rect.fTop + rad);
681 verts[3].set(rect.fRight + rad, rect.fTop - rad);
682 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
683 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
684 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
685 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
686 verts[8] = verts[0];
687 verts[9] = verts[1];
688}
689
bsalomon@google.com205d4602011-04-25 12:43:45 +0000690static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000691 // FIXME: This was copied from SkGpuDevice, seems like
692 // we should have already smeared a in caller if that
693 // is what is desired.
694 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000695 unsigned a = GrColorUnpackA(paint.fColor);
696 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000697 } else {
698 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000699 }
700}
701
702static void setInsetFan(GrPoint* pts, size_t stride,
703 const GrRect& r, GrScalar dx, GrScalar dy) {
704 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
705}
706
707static const uint16_t gFillAARectIdx[] = {
708 0, 1, 5, 5, 4, 0,
709 1, 2, 6, 6, 5, 1,
710 2, 3, 7, 7, 6, 2,
711 3, 0, 4, 4, 7, 3,
712 4, 5, 6, 6, 7, 4,
713};
714
715int GrContext::aaFillRectIndexCount() const {
716 return GR_ARRAY_COUNT(gFillAARectIdx);
717}
718
719GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
720 if (NULL == fAAFillRectIndexBuffer) {
721 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
722 false);
723 GrAssert(NULL != fAAFillRectIndexBuffer);
724#if GR_DEBUG
725 bool updated =
726#endif
727 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
728 sizeof(gFillAARectIdx));
729 GR_DEBUGASSERT(updated);
730 }
731 return fAAFillRectIndexBuffer;
732}
733
734static const uint16_t gStrokeAARectIdx[] = {
735 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
736 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
737 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
738 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
739
740 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
741 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
742 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
743 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
744
745 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
746 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
747 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
748 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
749};
750
751int GrContext::aaStrokeRectIndexCount() const {
752 return GR_ARRAY_COUNT(gStrokeAARectIdx);
753}
754
755GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
756 if (NULL == fAAStrokeRectIndexBuffer) {
757 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
758 false);
759 GrAssert(NULL != fAAStrokeRectIndexBuffer);
760#if GR_DEBUG
761 bool updated =
762#endif
763 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
764 sizeof(gStrokeAARectIdx));
765 GR_DEBUGASSERT(updated);
766 }
767 return fAAStrokeRectIndexBuffer;
768}
769
770void GrContext::fillAARect(GrDrawTarget* target,
771 const GrPaint& paint,
772 const GrRect& devRect) {
773
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000774 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
775 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000776
777 size_t vsize = GrDrawTarget::VertexSize(layout);
778
779 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
780
781 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
782
783 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
784 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
785
786 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
787 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
788
789 verts += sizeof(GrPoint);
790 for (int i = 0; i < 4; ++i) {
791 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
792 }
793
794 GrColor innerColor = getColorForMesh(paint);
795 verts += 4 * vsize;
796 for (int i = 0; i < 4; ++i) {
797 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
798 }
799
800 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
801
802 target->drawIndexed(kTriangles_PrimitiveType, 0,
803 0, 8, this->aaFillRectIndexCount());
804}
805
806void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
807 const GrRect& devRect, const GrVec& devStrokeSize) {
808 const GrScalar& dx = devStrokeSize.fX;
809 const GrScalar& dy = devStrokeSize.fY;
810 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
811 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
812
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000813 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
814 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000815
816 GrScalar spare;
817 {
818 GrScalar w = devRect.width() - dx;
819 GrScalar h = devRect.height() - dy;
820 spare = GrMin(w, h);
821 }
822
823 if (spare <= 0) {
824 GrRect r(devRect);
825 r.inset(-rx, -ry);
826 fillAARect(target, paint, r);
827 return;
828 }
829
830 size_t vsize = GrDrawTarget::VertexSize(layout);
831
832 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
833
834 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
835
836 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
837 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
838 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
839 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
840
841 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
842 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
843 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
844 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
845
846 verts += sizeof(GrPoint);
847 for (int i = 0; i < 4; ++i) {
848 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
849 }
850
851 GrColor innerColor = getColorForMesh(paint);
852 verts += 4 * vsize;
853 for (int i = 0; i < 8; ++i) {
854 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
855 }
856
857 verts += 8 * vsize;
858 for (int i = 0; i < 8; ++i) {
859 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
860 }
861
862 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
863 target->drawIndexed(kTriangles_PrimitiveType,
864 0, 0, 16, aaStrokeRectIndexCount());
865}
866
reed@google.com20efde72011-05-09 17:00:02 +0000867/**
868 * Returns true if the rects edges are integer-aligned.
869 */
870static bool isIRect(const GrRect& r) {
871 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
872 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
873}
874
bsalomon@google.com205d4602011-04-25 12:43:45 +0000875static bool apply_aa_to_rect(GrDrawTarget* target,
876 GrGpu* gpu,
877 const GrPaint& paint,
878 const GrRect& rect,
879 GrScalar width,
880 const GrMatrix* matrix,
881 GrMatrix* combinedMatrix,
882 GrRect* devRect) {
883 // we use a simple alpha ramp to do aa on axis-aligned rects
884 // do AA with alpha ramp if the caller requested AA, the rect
885 // will be axis-aligned,the render target is not
886 // multisampled, and the rect won't land on integer coords.
887
888 if (!paint.fAntiAlias) {
889 return false;
890 }
891
892 if (target->getRenderTarget()->isMultisampled()) {
893 return false;
894 }
895
896 if (0 == width && gpu->supportsAALines()) {
897 return false;
898 }
899
900 if (!target->getViewMatrix().preservesAxisAlignment()) {
901 return false;
902 }
903
904 if (NULL != matrix &&
905 !matrix->preservesAxisAlignment()) {
906 return false;
907 }
908
909 *combinedMatrix = target->getViewMatrix();
910 if (NULL != matrix) {
911 combinedMatrix->preConcat(*matrix);
912 GrAssert(combinedMatrix->preservesAxisAlignment());
913 }
914
915 combinedMatrix->mapRect(devRect, rect);
916 devRect->sort();
917
918 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000919 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000920 } else {
921 return true;
922 }
923}
924
bsalomon@google.com27847de2011-02-22 20:59:41 +0000925void GrContext::drawRect(const GrPaint& paint,
926 const GrRect& rect,
927 GrScalar width,
928 const GrMatrix* matrix) {
929
bsalomon@google.com27847de2011-02-22 20:59:41 +0000930
931 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000932 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000933
bsalomon@google.com205d4602011-04-25 12:43:45 +0000934 GrRect devRect = rect;
935 GrMatrix combinedMatrix;
936 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
937 &combinedMatrix, &devRect);
938
939 if (doAA) {
940 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000941 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000942 GrMatrix inv;
943 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000944 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000945 }
946 }
947 target->setViewMatrix(GrMatrix::I());
948 if (width >= 0) {
949 GrVec strokeSize;;
950 if (width > 0) {
951 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000952 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000953 strokeSize.setAbs(strokeSize);
954 } else {
955 strokeSize.set(GR_Scalar1, GR_Scalar1);
956 }
957 strokeAARect(target, paint, devRect, strokeSize);
958 } else {
959 fillAARect(target, paint, devRect);
960 }
961 return;
962 }
963
bsalomon@google.com27847de2011-02-22 20:59:41 +0000964 if (width >= 0) {
965 // TODO: consider making static vertex buffers for these cases.
966 // Hairline could be done by just adding closing vertex to
967 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000968 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
969
bsalomon@google.com27847de2011-02-22 20:59:41 +0000970 static const int worstCaseVertCount = 10;
971 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
972
973 if (!geo.succeeded()) {
974 return;
975 }
976
977 GrPrimitiveType primType;
978 int vertCount;
979 GrPoint* vertex = geo.positions();
980
981 if (width > 0) {
982 vertCount = 10;
983 primType = kTriangleStrip_PrimitiveType;
984 setStrokeRectStrip(vertex, rect, width);
985 } else {
986 // hairline
987 vertCount = 5;
988 primType = kLineStrip_PrimitiveType;
989 vertex[0].set(rect.fLeft, rect.fTop);
990 vertex[1].set(rect.fRight, rect.fTop);
991 vertex[2].set(rect.fRight, rect.fBottom);
992 vertex[3].set(rect.fLeft, rect.fBottom);
993 vertex[4].set(rect.fLeft, rect.fTop);
994 }
995
996 GrDrawTarget::AutoViewMatrixRestore avmr;
997 if (NULL != matrix) {
998 avmr.set(target);
999 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001000 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001001 }
1002
1003 target->drawNonIndexed(primType, 0, vertCount);
1004 } else {
1005 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001006 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1007
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001008 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001009 fGpu->getUnitSquareVertexBuffer());
1010 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1011 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001012 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001013 0, rect.height(), rect.fTop,
1014 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001015
1016 if (NULL != matrix) {
1017 m.postConcat(*matrix);
1018 }
1019
1020 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001021 target->preConcatSamplerMatrices(stageMask, m);
1022
bsalomon@google.com27847de2011-02-22 20:59:41 +00001023 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1024 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001025 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001026 #endif
1027 }
1028}
1029
1030void GrContext::drawRectToRect(const GrPaint& paint,
1031 const GrRect& dstRect,
1032 const GrRect& srcRect,
1033 const GrMatrix* dstMatrix,
1034 const GrMatrix* srcMatrix) {
1035
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001036 // srcRect refers to paint's first texture
1037 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001038 drawRect(paint, dstRect, -1, dstMatrix);
1039 return;
1040 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001041
bsalomon@google.com27847de2011-02-22 20:59:41 +00001042 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1043
1044#if GR_STATIC_RECT_VB
1045 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001046
1047 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001048 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1049
1050 GrMatrix m;
1051
1052 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1053 0, dstRect.height(), dstRect.fTop,
1054 0, 0, GrMatrix::I()[8]);
1055 if (NULL != dstMatrix) {
1056 m.postConcat(*dstMatrix);
1057 }
1058 target->preConcatViewMatrix(m);
1059
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001060 // srcRect refers to first stage
1061 int otherStageMask = paint.getActiveStageMask() &
1062 (~(1 << GrPaint::kFirstTextureStage));
1063 if (otherStageMask) {
1064 target->preConcatSamplerMatrices(otherStageMask, m);
1065 }
1066
bsalomon@google.com27847de2011-02-22 20:59:41 +00001067 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1068 0, srcRect.height(), srcRect.fTop,
1069 0, 0, GrMatrix::I()[8]);
1070 if (NULL != srcMatrix) {
1071 m.postConcat(*srcMatrix);
1072 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001073 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001074
1075 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1076 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1077#else
1078
1079 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001080#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001081 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001082#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001083 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1084#endif
1085
1086 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1087 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1088 srcRects[0] = &srcRect;
1089 srcMatrices[0] = srcMatrix;
1090
1091 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1092#endif
1093}
1094
1095void GrContext::drawVertices(const GrPaint& paint,
1096 GrPrimitiveType primitiveType,
1097 int vertexCount,
1098 const GrPoint positions[],
1099 const GrPoint texCoords[],
1100 const GrColor colors[],
1101 const uint16_t indices[],
1102 int indexCount) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001103
1104 GrDrawTarget::AutoReleaseGeometry geo;
1105
1106 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1107
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001108 bool hasTexCoords[GrPaint::kTotalStages] = {
1109 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1110 0 // remaining stages use positions
1111 };
1112
1113 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001114
1115 if (NULL != colors) {
1116 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001117 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001118 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001119
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001120 bool doAA = false;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001121 OffscreenRecord record;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001122 GrIRect bounds;
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001123
bsalomon@google.com27847de2011-02-22 20:59:41 +00001124 if (sizeof(GrPoint) != vertexSize) {
1125 if (!geo.set(target, layout, vertexCount, 0)) {
1126 GrPrintf("Failed to get space for vertices!");
1127 return;
1128 }
1129 int texOffsets[GrDrawTarget::kMaxTexCoords];
1130 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001131 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1132 texOffsets,
1133 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001134 void* curVertex = geo.vertices();
1135
1136 for (int i = 0; i < vertexCount; ++i) {
1137 *((GrPoint*)curVertex) = positions[i];
1138
1139 if (texOffsets[0] > 0) {
1140 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1141 }
1142 if (colorOffset > 0) {
1143 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1144 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001145 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 }
1147 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001148 // we don't do offscreen AA when we have per-vertex tex coords or colors
1149 if (this->doOffscreenAA(target, paint, GrIsPrimTypeLines(primitiveType))) {
1150 GrRect b;
1151 b.setBounds(positions, vertexCount);
1152 target->getViewMatrix().mapRect(&b);
1153 b.roundOut(&bounds);
1154
1155 if (this->setupOffscreenAAPass1(target, false, bounds, &record)) {
1156 doAA = true;
1157 }
1158 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159 target->setVertexSourceToArray(layout, positions, vertexCount);
1160 }
1161
1162 if (NULL != indices) {
1163 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001164 }
1165
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001166 if (NULL != indices) {
1167 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001168 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001169 target->drawNonIndexed(primitiveType, 0, vertexCount);
1170 }
1171
1172 if (doAA) {
1173 this->offscreenAAPass2(target, paint, bounds, &record);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001174 }
1175}
1176
1177
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001178///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001179
reed@google.com07f3ee12011-05-16 17:21:57 +00001180void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1181 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001182
bsalomon@google.com27847de2011-02-22 20:59:41 +00001183 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001184 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001185
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001186 if (!IsFillInverted(fill) && // will be relaxed soon
1187 !pr->supportsAA(target, path, fill) &&
1188 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001189
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001190 OffscreenRecord record;
1191 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001192
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001193 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001194 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1195 target->getRenderTarget()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001196 if (target->getClip().hasConservativeBounds()) {
1197 GrIRect clipIBounds;
1198 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001199 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001200 return;
1201 }
1202 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001203 GrRect pathBounds = path.getBounds();
1204 if (!pathBounds.isEmpty()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001205 GrIRect pathIBounds;
1206 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
1207 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001208 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001209 return;
1210 }
1211 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001212
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001213 if (this->setupOffscreenAAPass1(target, needsStencil, bound, &record)) {
1214 pr->drawPath(target, 0, path, fill, translate);
1215 this->offscreenAAPass2(target, paint, bound, &record);
1216 return;
1217 }
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001218 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001219 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001220
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001221 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001222}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001223
bsalomon@google.com27847de2011-02-22 20:59:41 +00001224////////////////////////////////////////////////////////////////////////////////
1225
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001226void GrContext::flush(int flagsBitfield) {
1227 if (kDiscard_FlushBit & flagsBitfield) {
1228 fDrawBuffer->reset();
1229 } else {
1230 flushDrawBuffer();
1231 }
1232
1233 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234 fGpu->forceRenderTargetFlush();
1235 }
1236}
1237
1238void GrContext::flushText() {
1239 if (kText_DrawCategory == fLastDrawCategory) {
1240 flushDrawBuffer();
1241 }
1242}
1243
1244void GrContext::flushDrawBuffer() {
1245#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
1246 fDrawBuffer->playback(fGpu);
1247 fDrawBuffer->reset();
1248#endif
1249}
1250
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001251bool GrContext::readTexturePixels(GrTexture* texture,
1252 int left, int top, int width, int height,
1253 GrPixelConfig config, void* buffer) {
1254
1255 // TODO: code read pixels for textures that aren't rendertargets
1256
1257 this->flush();
1258 GrRenderTarget* target = texture->asRenderTarget();
1259 if (NULL != target) {
1260 return fGpu->readPixels(target,
1261 left, top, width, height,
1262 config, buffer);
1263 } else {
1264 return false;
1265 }
1266}
1267
1268bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1269 int left, int top, int width, int height,
1270 GrPixelConfig config, void* buffer) {
1271 uint32_t flushFlags = 0;
1272 if (NULL == target) {
1273 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1274 }
1275
1276 this->flush(flushFlags);
1277 return fGpu->readPixels(target,
1278 left, top, width, height,
1279 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001280}
1281
1282void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001283 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001284 size_t stride) {
1285
1286 // TODO: when underlying api has a direct way to do this we should use it
1287 // (e.g. glDrawPixels on desktop GL).
1288
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001289 const GrTextureDesc desc = {
1290 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001291 };
1292 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1293 if (NULL == texture) {
1294 return;
1295 }
1296
1297 this->flush(true);
1298
1299 GrAutoUnref aur(texture);
1300 GrDrawTarget::AutoStateRestore asr(fGpu);
1301
1302 GrMatrix matrix;
1303 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1304 fGpu->setViewMatrix(matrix);
1305
1306 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1307 fGpu->setAlpha(0xFF);
1308 fGpu->setBlendFunc(kOne_BlendCoeff,
1309 kZero_BlendCoeff);
1310 fGpu->setTexture(0, texture);
1311
1312 GrSamplerState sampler;
1313 sampler.setClampNoFilter();
1314 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1315 sampler.setMatrix(matrix);
1316 fGpu->setSamplerState(0, sampler);
1317
1318 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1319 static const int VCOUNT = 4;
1320
1321 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1322 if (!geo.succeeded()) {
1323 return;
1324 }
1325 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1326 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1327}
1328////////////////////////////////////////////////////////////////////////////////
1329
1330void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001331
1332 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1333 int s = i + GrPaint::kFirstTextureStage;
1334 target->setTexture(s, paint.getTexture(i));
1335 target->setSamplerState(s, *paint.getTextureSampler(i));
1336 }
1337
1338 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1339
1340 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1341 int s = i + GrPaint::kFirstMaskStage;
1342 target->setTexture(s, paint.getMask(i));
1343 target->setSamplerState(s, *paint.getMaskSampler(i));
1344 }
1345
bsalomon@google.com27847de2011-02-22 20:59:41 +00001346 target->setColor(paint.fColor);
1347
1348 if (paint.fDither) {
1349 target->enableState(GrDrawTarget::kDither_StateBit);
1350 } else {
1351 target->disableState(GrDrawTarget::kDither_StateBit);
1352 }
1353 if (paint.fAntiAlias) {
1354 target->enableState(GrDrawTarget::kAntialias_StateBit);
1355 } else {
1356 target->disableState(GrDrawTarget::kAntialias_StateBit);
1357 }
1358 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001359 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001360}
1361
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001362GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001363 DrawCategory category) {
1364 if (category != fLastDrawCategory) {
1365 flushDrawBuffer();
1366 fLastDrawCategory = category;
1367 }
1368 SetPaint(paint, fGpu);
1369 GrDrawTarget* target = fGpu;
1370 switch (category) {
1371 case kText_DrawCategory:
1372#if DEFER_TEXT_RENDERING
1373 target = fDrawBuffer;
1374 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1375#else
1376 target = fGpu;
1377#endif
1378 break;
1379 case kUnbuffered_DrawCategory:
1380 target = fGpu;
1381 break;
1382 case kBuffered_DrawCategory:
1383 target = fDrawBuffer;
1384 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1385 break;
1386 }
1387 return target;
1388}
1389
1390////////////////////////////////////////////////////////////////////////////////
1391
bsalomon@google.com27847de2011-02-22 20:59:41 +00001392void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001393 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001394 fGpu->setRenderTarget(target);
1395}
1396
1397GrRenderTarget* GrContext::getRenderTarget() {
1398 return fGpu->getRenderTarget();
1399}
1400
1401const GrRenderTarget* GrContext::getRenderTarget() const {
1402 return fGpu->getRenderTarget();
1403}
1404
1405const GrMatrix& GrContext::getMatrix() const {
1406 return fGpu->getViewMatrix();
1407}
1408
1409void GrContext::setMatrix(const GrMatrix& m) {
1410 fGpu->setViewMatrix(m);
1411}
1412
1413void GrContext::concatMatrix(const GrMatrix& m) const {
1414 fGpu->preConcatViewMatrix(m);
1415}
1416
1417static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1418 intptr_t mask = 1 << shift;
1419 if (pred) {
1420 bits |= mask;
1421 } else {
1422 bits &= ~mask;
1423 }
1424 return bits;
1425}
1426
1427void GrContext::resetStats() {
1428 fGpu->resetStats();
1429}
1430
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001431const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001432 return fGpu->getStats();
1433}
1434
1435void GrContext::printStats() const {
1436 fGpu->printStats();
1437}
1438
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001439GrContext::GrContext(GrGpu* gpu) :
1440 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1441 gpu->supportsStencilWrapOps()) {
1442
bsalomon@google.com27847de2011-02-22 20:59:41 +00001443 fGpu = gpu;
1444 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001445 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001446
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001447 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1448 fGpu->setClipPathRenderer(fCustomPathRenderer);
1449
bsalomon@google.com27847de2011-02-22 20:59:41 +00001450 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1451 MAX_TEXTURE_CACHE_BYTES);
1452 fFontCache = new GrFontCache(fGpu);
1453
1454 fLastDrawCategory = kUnbuffered_DrawCategory;
1455
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001456 fDrawBuffer = NULL;
1457 fDrawBufferVBAllocPool = NULL;
1458 fDrawBufferIBAllocPool = NULL;
1459
bsalomon@google.com205d4602011-04-25 12:43:45 +00001460 fAAFillRectIndexBuffer = NULL;
1461 fAAStrokeRectIndexBuffer = NULL;
1462
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001463 this->setupDrawBuffer();
1464}
1465
1466void GrContext::setupDrawBuffer() {
1467
1468 GrAssert(NULL == fDrawBuffer);
1469 GrAssert(NULL == fDrawBufferVBAllocPool);
1470 GrAssert(NULL == fDrawBufferIBAllocPool);
1471
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001473 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001474 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001475 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1476 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001477 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001478 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001479 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001480 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1481
1482 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1483 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001484#endif
1485
1486#if BATCH_RECT_TO_RECT
1487 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1488#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001489}
1490
bsalomon@google.com27847de2011-02-22 20:59:41 +00001491GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1492 GrDrawTarget* target;
1493#if DEFER_TEXT_RENDERING
1494 target = prepareToDraw(paint, kText_DrawCategory);
1495#else
1496 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1497#endif
1498 SetPaint(paint, target);
1499 return target;
1500}
1501
1502const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1503 return fGpu->getQuadIndexBuffer();
1504}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001505
1506GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001507 const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001508 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001509 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001510 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1511 return fCustomPathRenderer;
1512 } else {
1513 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1514 return &fDefaultPathRenderer;
1515 }
1516}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001517