blob: 975f6d0b90372624ff72af37f923632a4f244469 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.com1fadb202011-12-12 16:10:08 +000010#include "GrContext.h"
11
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000014#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015#include "GrIndexBuffer.h"
16#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000017#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000018#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000020#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000021#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000022#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000023#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024
bsalomon@google.com91958362011-06-13 17:58:13 +000025// Using MSAA seems to be slower for some yet unknown reason.
26#define PREFER_MSAA_OFFSCREEN_AA 0
27#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000028
bsalomon@google.com27847de2011-02-22 20:59:41 +000029#define DEFER_TEXT_RENDERING 1
30
31#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
32
bsalomon@google.comd46e2422011-09-23 17:40:07 +000033// When we're using coverage AA but the blend is incompatible (given gpu
34// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000035#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000036
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000037static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000039
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
bsalomon@google.combc4b6542011-11-19 13:56:11 +000048#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
49
bsalomon@google.com05ef5102011-05-02 21:14:59 +000050GrContext* GrContext::Create(GrEngine engine,
51 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000052 GrContext* ctx = NULL;
53 GrGpu* fGpu = GrGpu::Create(engine, context3D);
54 if (NULL != fGpu) {
55 ctx = new GrContext(fGpu);
56 fGpu->unref();
57 }
58 return ctx;
59}
60
bsalomon@google.com27847de2011-02-22 20:59:41 +000061GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000068
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000072 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000073}
74
bsalomon@google.com8fe72472011-03-30 21:26:44 +000075void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000076 contextDestroyed();
77 this->setupDrawBuffer();
78}
79
80void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 // abandon first to so destructors
82 // don't try to free the resources in the API.
83 fGpu->abandonResources();
84
bsalomon@google.com30085192011-08-19 15:42:31 +000085 // a path renderer may be holding onto resources that
86 // are now unusable
87 GrSafeSetNull(fPathRendererChain);
88
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBuffer;
90 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferVBAllocPool;
93 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000094
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 delete fDrawBufferIBAllocPool;
96 fDrawBufferIBAllocPool = NULL;
97
bsalomon@google.com205d4602011-04-25 12:43:45 +000098 GrSafeSetNull(fAAFillRectIndexBuffer);
99 GrSafeSetNull(fAAStrokeRectIndexBuffer);
100
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101 fTextureCache->removeAll();
102 fFontCache->freeAll();
103 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000104}
105
106void GrContext::resetContext() {
107 fGpu->markContextDirty();
108}
109
110void GrContext::freeGpuResources() {
111 this->flush();
112 fTextureCache->removeAll();
113 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000114 // a path renderer may be holding onto resources
115 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000116}
117
twiz@google.com05e70242012-01-27 19:12:00 +0000118size_t GrContext::getGpuTextureCacheBytes() const {
119 return fTextureCache->getCachedResourceBytes();
120}
121
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000122////////////////////////////////////////////////////////////////////////////////
123
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000124int GrContext::PaintStageVertexLayoutBits(
125 const GrPaint& paint,
126 const bool hasTexCoords[GrPaint::kTotalStages]) {
127 int stageMask = paint.getActiveStageMask();
128 int layout = 0;
129 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
130 if ((1 << i) & stageMask) {
131 if (NULL != hasTexCoords && hasTexCoords[i]) {
132 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
133 } else {
134 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
135 }
136 }
137 }
138 return layout;
139}
140
141
142////////////////////////////////////////////////////////////////////////////////
143
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000144enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000145 // flags for textures
146 kNPOTBit = 0x1,
147 kFilterBit = 0x2,
148 kScratchBit = 0x4,
149
150 // resource type
151 kTextureBit = 0x8,
152 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000153};
154
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000155GrTexture* GrContext::TextureCacheEntry::texture() const {
156 if (NULL == fEntry) {
157 return NULL;
158 } else {
159 return (GrTexture*) fEntry->resource();
160 }
161}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000162
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163namespace {
164// returns true if this is a "special" texture because of gpu NPOT limitations
165bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000166 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000167 GrContext::TextureKey clientKey,
168 int width,
169 int height,
170 bool scratch,
171 uint32_t v[4]) {
172 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
173 // we assume we only need 16 bits of width and height
174 // assert that texture creation will fail anyway if this assumption
175 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000176 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000177 v[0] = clientKey & 0xffffffffUL;
178 v[1] = (clientKey >> 32) & 0xffffffffUL;
179 v[2] = width | (height << 16);
180
181 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000182 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000183 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
184
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000185 bool tiled = NULL != sampler &&
186 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
187 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000188
189 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000190 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000191 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000192 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000193 }
194 }
195 }
196
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000197 if (scratch) {
198 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000199 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000200
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000201 v[3] |= kTextureBit;
202
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000203 return v[3] & kNPOTBit;
204}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000205
206// we should never have more than one stencil buffer with same combo of
207// (width,height,samplecount)
208void gen_stencil_key_values(int width, int height,
209 int sampleCnt, uint32_t v[4]) {
210 v[0] = width;
211 v[1] = height;
212 v[2] = sampleCnt;
213 v[3] = kStencilBufferBit;
214}
215
216void gen_stencil_key_values(const GrStencilBuffer* sb,
217 uint32_t v[4]) {
218 gen_stencil_key_values(sb->width(), sb->height(),
219 sb->numSamples(), v);
220}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000221
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000222}
223
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000224GrContext::TextureCacheEntry GrContext::findAndLockTexture(
225 TextureKey key,
226 int width,
227 int height,
228 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000229 uint32_t v[4];
230 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
231 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000232 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
233 GrResourceCache::kNested_LockType));
234}
235
bsalomon@google.comfb309512011-11-30 14:13:48 +0000236bool GrContext::isTextureInCache(TextureKey key,
237 int width,
238 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000239 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000240 uint32_t v[4];
241 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
242 GrResourceKey resourceKey(v);
243 return fTextureCache->hasKey(resourceKey);
244}
245
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000246GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000247 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000248 uint32_t v[4];
249 gen_stencil_key_values(sb, v);
250 GrResourceKey resourceKey(v);
251 return fTextureCache->createAndLock(resourceKey, sb);
252}
253
254GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
255 int sampleCnt) {
256 uint32_t v[4];
257 gen_stencil_key_values(width, height, sampleCnt, v);
258 GrResourceKey resourceKey(v);
259 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
260 GrResourceCache::kSingle_LockType);
261 if (NULL != entry) {
262 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
263 return sb;
264 } else {
265 return NULL;
266 }
267}
268
269void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000270 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000271 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000272}
273
274static void stretchImage(void* dst,
275 int dstW,
276 int dstH,
277 void* src,
278 int srcW,
279 int srcH,
280 int bpp) {
281 GrFixed dx = (srcW << 16) / dstW;
282 GrFixed dy = (srcH << 16) / dstH;
283
284 GrFixed y = dy >> 1;
285
286 int dstXLimit = dstW*bpp;
287 for (int j = 0; j < dstH; ++j) {
288 GrFixed x = dx >> 1;
289 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
290 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
291 for (int i = 0; i < dstXLimit; i += bpp) {
292 memcpy((uint8_t*) dstRow + i,
293 (uint8_t*) srcRow + (x>>16)*bpp,
294 bpp);
295 x += dx;
296 }
297 y += dy;
298 }
299}
300
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000301GrContext::TextureCacheEntry GrContext::createAndLockTexture(
302 TextureKey key,
303 const GrSamplerState* sampler,
304 const GrTextureDesc& desc,
305 void* srcData,
306 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000307 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000308
309#if GR_DUMP_TEXTURE_UPLOAD
310 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
311#endif
312
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000313 TextureCacheEntry entry;
314 uint32_t v[4];
315 bool special = gen_texture_key_values(fGpu, sampler, key,
316 desc.fWidth, desc.fHeight, false, v);
317 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000318
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000319 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000320 GrAssert(NULL != sampler);
321 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
322 desc.fWidth,
323 desc.fHeight,
324 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000325
326 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000327 clampEntry = this->createAndLockTexture(key, NULL, desc,
328 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000329 GrAssert(NULL != clampEntry.texture());
330 if (NULL == clampEntry.texture()) {
331 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000332 }
333 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000334 GrTextureDesc rtDesc = desc;
335 rtDesc.fFlags = rtDesc.fFlags |
336 kRenderTarget_GrTextureFlagBit |
337 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000338 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
339 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000340
341 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
342
343 if (NULL != texture) {
344 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000345 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000346 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000347 drawState->setRenderTarget(texture->asRenderTarget());
348 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000349
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000350 GrSamplerState::Filter filter;
351 // if filtering is not desired then we want to ensure all
352 // texels in the resampled image are copies of texels from
353 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000354 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000355 filter = GrSamplerState::kNearest_Filter;
356 } else {
357 filter = GrSamplerState::kBilinear_Filter;
358 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000359 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
360 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000361
362 static const GrVertexLayout layout =
363 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
364 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
365
366 if (arg.succeeded()) {
367 GrPoint* verts = (GrPoint*) arg.vertices();
368 verts[0].setIRectFan(0, 0,
369 texture->width(),
370 texture->height(),
371 2*sizeof(GrPoint));
372 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
373 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
374 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000375 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000376 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000377 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000378 } else {
379 // TODO: Our CPU stretch doesn't filter. But we create separate
380 // stretched textures when the sampler state is either filtered or
381 // not. Either implement filtered stretch blit on CPU or just create
382 // one when FBO case fails.
383
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000384 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000385 // no longer need to clamp at min RT size.
386 rtDesc.fWidth = GrNextPow2(desc.fWidth);
387 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000388 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000389 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000390 rtDesc.fWidth *
391 rtDesc.fHeight);
392 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
393 srcData, desc.fWidth, desc.fHeight, bpp);
394
395 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
396
397 GrTexture* texture = fGpu->createTexture(rtDesc,
398 stretchedPixels.get(),
399 stretchedRowBytes);
400 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000401 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000404
405 } else {
406 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
407 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000408 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000409 }
410 }
411 return entry;
412}
413
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414namespace {
415inline void gen_scratch_tex_key_values(const GrGpu* gpu,
416 const GrTextureDesc& desc,
417 uint32_t v[4]) {
418 // Instead of a client-provided key of the texture contents
419 // we create a key of from the descriptor.
420 GrContext::TextureKey descKey = desc.fAALevel |
421 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000422 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000423 // this code path isn't friendly to tiling with NPOT restricitons
424 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000425 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
426 desc.fHeight, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000428}
429
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000430GrContext::TextureCacheEntry GrContext::lockScratchTexture(
431 const GrTextureDesc& inDesc,
432 ScratchTexMatch match) {
433
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000434 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000435 if (kExact_ScratchTexMatch != match) {
436 // bin by pow2 with a reasonable min
437 static const int MIN_SIZE = 256;
438 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
439 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
440 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000441
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000442 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000443 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
444
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000445 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000446 int origWidth = desc.fWidth;
447 int origHeight = desc.fHeight;
448 bool doubledW = false;
449 bool doubledH = false;
450
451 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000452 uint32_t v[4];
453 gen_scratch_tex_key_values(fGpu, desc, v);
454 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000455 entry = fTextureCache->findAndLock(key,
456 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000457 // if we miss, relax the fit of the flags...
458 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000459 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000460 break;
461 }
462 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
463 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
464 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
465 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
466 } else if (!doubledW) {
467 desc.fFlags = inDesc.fFlags;
468 desc.fWidth *= 2;
469 doubledW = true;
470 } else if (!doubledH) {
471 desc.fFlags = inDesc.fFlags;
472 desc.fWidth = origWidth;
473 desc.fHeight *= 2;
474 doubledH = true;
475 } else {
476 break;
477 }
478
479 } while (true);
480
481 if (NULL == entry) {
482 desc.fFlags = inDesc.fFlags;
483 desc.fWidth = origWidth;
484 desc.fHeight = origHeight;
485 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
486 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000487 uint32_t v[4];
488 gen_scratch_tex_key_values(fGpu, desc, v);
489 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000490 entry = fTextureCache->createAndLock(key, texture);
491 }
492 }
493
494 // If the caller gives us the same desc/sampler twice we don't want
495 // to return the same texture the second time (unless it was previously
496 // released). So we detach the entry from the cache and reattach at release.
497 if (NULL != entry) {
498 fTextureCache->detach(entry);
499 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000500 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000501}
502
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000503void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000504 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000505 // If this is a scratch texture we detached it from the cache
506 // while it was locked (to avoid two callers simultaneously getting
507 // the same texture).
508 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
509 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000510 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000511 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000512 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000513}
514
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000515GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000516 void* srcData,
517 size_t rowBytes) {
518 return fGpu->createTexture(desc, srcData, rowBytes);
519}
520
521void GrContext::getTextureCacheLimits(int* maxTextures,
522 size_t* maxTextureBytes) const {
523 fTextureCache->getLimits(maxTextures, maxTextureBytes);
524}
525
526void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
527 fTextureCache->setLimits(maxTextures, maxTextureBytes);
528}
529
bsalomon@google.com91958362011-06-13 17:58:13 +0000530int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000531 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000532}
533
534int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000535 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000536}
537
538///////////////////////////////////////////////////////////////////////////////
539
bsalomon@google.come269f212011-11-07 13:29:52 +0000540GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
541 return fGpu->createPlatformTexture(desc);
542}
543
544GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
545 return fGpu->createPlatformRenderTarget(desc);
546}
547
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000548///////////////////////////////////////////////////////////////////////////////
549
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000550bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000551 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000552 const GrDrawTarget::Caps& caps = fGpu->getCaps();
553 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000554 return false;
555 }
556
bsalomon@google.com27847de2011-02-22 20:59:41 +0000557 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
558
559 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000560 bool tiled = NULL != sampler &&
561 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
562 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000563 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000564 return false;
565 }
566 }
567 return true;
568}
569
570////////////////////////////////////////////////////////////////////////////////
571
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000572const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
573
bsalomon@google.com27847de2011-02-22 20:59:41 +0000574void GrContext::setClip(const GrClip& clip) {
575 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000576 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577}
578
579void GrContext::setClip(const GrIRect& rect) {
580 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000581 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000582 fGpu->setClip(clip);
583}
584
585////////////////////////////////////////////////////////////////////////////////
586
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000587void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000588 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000589 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000590}
591
592void GrContext::drawPaint(const GrPaint& paint) {
593 // set rect to be big enough to fill the space, but not super-huge, so we
594 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000595 GrRect r;
596 r.setLTRB(0, 0,
597 GrIntToScalar(getRenderTarget()->width()),
598 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000599 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000600 SkTLazy<GrPaint> tmpPaint;
601 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000602 GrDrawState* drawState = fGpu->drawState();
603 GrAutoMatrix am;
604
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000605 // We attempt to map r by the inverse matrix and draw that. mapRect will
606 // map the four corners and bound them with a new rect. This will not
607 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000608 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000609 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000610 GrPrintf("Could not invert matrix");
611 return;
612 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000613 inverse.mapRect(&r);
614 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000615 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000616 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000617 GrPrintf("Could not invert matrix");
618 return;
619 }
620 tmpPaint.set(paint);
621 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
622 p = tmpPaint.get();
623 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000624 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000625 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000626 // by definition this fills the entire clip, no need for AA
627 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000628 if (!tmpPaint.isValid()) {
629 tmpPaint.set(paint);
630 p = tmpPaint.get();
631 }
632 GrAssert(p == tmpPaint.get());
633 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000634 }
635 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000636}
637
bsalomon@google.com205d4602011-04-25 12:43:45 +0000638////////////////////////////////////////////////////////////////////////////////
639
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000640namespace {
641inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
642 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
643}
644}
645
bsalomon@google.com91958362011-06-13 17:58:13 +0000646struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000647 enum Downsample {
bsalomon@google.com91958362011-06-13 17:58:13 +0000648 k4x4SinglePass_Downsample,
649 kFSAA_Downsample
650 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000651 int fTileSizeX;
652 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000653 int fTileCountX;
654 int fTileCountY;
655 int fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000656 GrAutoScratchTexture fOffscreen;
bsalomon@google.com91958362011-06-13 17:58:13 +0000657 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000658 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000659};
660
bsalomon@google.com471d4712011-08-23 15:45:25 +0000661bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000662 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000663#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000664 return false;
665#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000666 // Line primitves are always rasterized as 1 pixel wide.
667 // Super-sampling would make them too thin but MSAA would be OK.
668 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000669 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000670 return false;
671 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000672 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000673 return false;
674 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000675 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000676#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000677 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000678#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000679 return false;
680 }
681 return true;
682#endif
683}
684
bsalomon@google.com91958362011-06-13 17:58:13 +0000685bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000686 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000687 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000688 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000689 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000690
691 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000692
bsalomon@google.com46579e02012-01-11 18:51:15 +0000693 GrAssert(NULL == record->fOffscreen.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000694 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000695
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000696 int boundW = boundRect.width();
697 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000698
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000699 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000700
701 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
702 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
703
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000704 if (requireStencil) {
705 desc.fFlags = kRenderTarget_GrTextureFlagBit;
706 } else {
707 desc.fFlags = kRenderTarget_GrTextureFlagBit |
708 kNoStencil_GrTextureFlagBit;
709 }
710
bsalomon@google.comc4364992011-11-07 15:54:49 +0000711 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000712
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000713 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000714 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000715 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000716 desc.fAALevel = kMed_GrAALevel;
717 } else {
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000718 record->fDownsample = OffscreenRecord::k4x4SinglePass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000719 record->fScale = OFFSCREEN_SSAA_SCALE;
720 // both downsample paths assume this
721 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000722 desc.fAALevel = kNone_GrAALevel;
723 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000724
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000725 desc.fWidth *= record->fScale;
726 desc.fHeight *= record->fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000727 record->fOffscreen.set(this, desc);
728 if (NULL == record->fOffscreen.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729 return false;
730 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000731 // the approximate lookup might have given us some slop space, might as well
732 // use it when computing the tiles size.
733 // these are scale values, will adjust after considering
734 // the possible second offscreen.
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000735 record->fTileSizeX = record->fOffscreen.texture()->width();
736 record->fTileSizeY = record->fOffscreen.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000737
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000738 record->fTileSizeX /= record->fScale;
739 record->fTileSizeY /= record->fScale;
740
741 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
742 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
743
tomhudson@google.com237a4612011-07-19 15:44:00 +0000744 record->fClip = target->getClip();
745
bsalomon@google.com91958362011-06-13 17:58:13 +0000746 target->saveCurrentDrawState(&record->fSavedState);
747 return true;
748}
749
750void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
751 const GrIRect& boundRect,
752 int tileX, int tileY,
753 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000754
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000755 GrRenderTarget* offRT = record->fOffscreen.texture()->asRenderTarget();
756 GrAssert(NULL != offRT);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000757
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000758 GrDrawState* drawState = target->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000759 GrMatrix vm = drawState->getViewMatrix();
760 drawState->reset();
761 *drawState->viewMatrix() = vm;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000762 drawState->setRenderTarget(offRT);
bsalomon@google.com46f7afb2012-01-18 19:51:55 +0000763
bsalomon@google.com289533a2011-10-27 12:34:25 +0000764#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com337af172012-01-11 16:00:42 +0000765 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000766#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000767
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000768 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000769 int left = boundRect.fLeft + tileX * record->fTileSizeX;
770 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000771 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000772 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000773 GrMatrix scaleM;
774 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000775 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000776
bsalomon@google.com91958362011-06-13 17:58:13 +0000777 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000778 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000779 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000780 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000781 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
782 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000783 target->setClip(GrClip(clear));
bsalomon@google.com46f7afb2012-01-18 19:51:55 +0000784 drawState->enableState(GrDrawState::kClip_StateBit);
785
bsalomon@google.com91958362011-06-13 17:58:13 +0000786#if 0
787 // visualize tile boundaries by setting edges of offscreen to white
788 // and interior to tranparent. black.
789 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000790
bsalomon@google.com91958362011-06-13 17:58:13 +0000791 static const int gOffset = 2;
792 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
793 record->fScale * w - gOffset,
794 record->fScale * h - gOffset);
795 target->clear(&clear2, 0x0);
796#else
797 target->clear(&clear, 0x0);
798#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000799}
800
bsalomon@google.com91958362011-06-13 17:58:13 +0000801void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000802 const GrPaint& paint,
803 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000804 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000805 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000806 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com46579e02012-01-11 18:51:15 +0000807 GrAssert(NULL != record->fOffscreen.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000808 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000809 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
811 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000812 tileRect.fRight = (tileX == record->fTileCountX-1) ?
813 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000814 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000815 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
816 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000817 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000818
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000819 GrSamplerState::Filter filter;
820 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
821 filter = GrSamplerState::k4x4Downsample_Filter;
822 } else {
823 filter = GrSamplerState::kBilinear_Filter;
824 }
825
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000826 GrTexture* src = record->fOffscreen.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000827 int scale;
828
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000829 enum {
830 kOffscreenStage = GrPaint::kTotalStages,
831 };
832
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000833 GrDrawState* drawState = target->drawState();
834
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000835 if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000836 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000837 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000838 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000839 } else {
840 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
841 record->fDownsample);
842 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000843 }
844
bsalomon@google.com91958362011-06-13 17:58:13 +0000845 // setup for draw back to main RT, we use the original
846 // draw state setup by the caller plus an additional coverage
847 // stage to handle the AA resolve. Also, we use an identity
848 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000849 int stageMask = paint.getActiveStageMask();
850
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000852 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000853
854 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000855 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000856 if (drawState->getViewInverse(&invVM)) {
857 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000858 }
859 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000860 // This is important when tiling, otherwise second tile's
861 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000862 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000863
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000864 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000865 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
866 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000867 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
868 scale * GR_Scalar1 / src->height());
869 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
870 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000871
reed@google.com20efde72011-05-09 17:00:02 +0000872 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000873 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000874 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000875 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000876}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000877
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000878void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
879 GrPathRenderer* pr,
880 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000881 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000882}
883
884////////////////////////////////////////////////////////////////////////////////
885
bsalomon@google.com27847de2011-02-22 20:59:41 +0000886/* create a triangle strip that strokes the specified triangle. There are 8
887 unique vertices, but we repreat the last 2 to close up. Alternatively we
888 could use an indices array, and then only send 8 verts, but not sure that
889 would be faster.
890 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000891static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000892 GrScalar width) {
893 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000894 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000895
896 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
897 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
898 verts[2].set(rect.fRight - rad, rect.fTop + rad);
899 verts[3].set(rect.fRight + rad, rect.fTop - rad);
900 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
901 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
902 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
903 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
904 verts[8] = verts[0];
905 verts[9] = verts[1];
906}
907
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908static void setInsetFan(GrPoint* pts, size_t stride,
909 const GrRect& r, GrScalar dx, GrScalar dy) {
910 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
911}
912
913static const uint16_t gFillAARectIdx[] = {
914 0, 1, 5, 5, 4, 0,
915 1, 2, 6, 6, 5, 1,
916 2, 3, 7, 7, 6, 2,
917 3, 0, 4, 4, 7, 3,
918 4, 5, 6, 6, 7, 4,
919};
920
921int GrContext::aaFillRectIndexCount() const {
922 return GR_ARRAY_COUNT(gFillAARectIdx);
923}
924
925GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
926 if (NULL == fAAFillRectIndexBuffer) {
927 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
928 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000929 if (NULL != fAAFillRectIndexBuffer) {
930 #if GR_DEBUG
931 bool updated =
932 #endif
933 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
934 sizeof(gFillAARectIdx));
935 GR_DEBUGASSERT(updated);
936 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000937 }
938 return fAAFillRectIndexBuffer;
939}
940
941static const uint16_t gStrokeAARectIdx[] = {
942 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
943 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
944 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
945 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
946
947 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
948 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
949 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
950 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
951
952 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
953 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
954 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
955 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
956};
957
958int GrContext::aaStrokeRectIndexCount() const {
959 return GR_ARRAY_COUNT(gStrokeAARectIdx);
960}
961
962GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
963 if (NULL == fAAStrokeRectIndexBuffer) {
964 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
965 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000966 if (NULL != fAAStrokeRectIndexBuffer) {
967 #if GR_DEBUG
968 bool updated =
969 #endif
970 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
971 sizeof(gStrokeAARectIdx));
972 GR_DEBUGASSERT(updated);
973 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000974 }
975 return fAAStrokeRectIndexBuffer;
976}
977
bsalomon@google.coma3108262011-10-10 14:08:47 +0000978static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
979 bool useCoverage) {
980 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000981 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000982 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000983 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
984 }
985 }
986 if (useCoverage) {
987 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
988 } else {
989 layout |= GrDrawTarget::kColor_VertexLayoutBit;
990 }
991 return layout;
992}
993
bsalomon@google.com205d4602011-04-25 12:43:45 +0000994void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000995 const GrRect& devRect,
996 bool useVertexCoverage) {
997 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000998
999 size_t vsize = GrDrawTarget::VertexSize(layout);
1000
1001 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001002 if (!geo.succeeded()) {
1003 GrPrintf("Failed to get space for vertices!\n");
1004 return;
1005 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001006 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1007 if (NULL == indexBuffer) {
1008 GrPrintf("Failed to create index buffer!\n");
1009 return;
1010 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001011
1012 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1013
1014 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1015 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1016
1017 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1018 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1019
1020 verts += sizeof(GrPoint);
1021 for (int i = 0; i < 4; ++i) {
1022 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1023 }
1024
bsalomon@google.coma3108262011-10-10 14:08:47 +00001025 GrColor innerColor;
1026 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001027 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001028 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001029 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001030 }
1031
bsalomon@google.com205d4602011-04-25 12:43:45 +00001032 verts += 4 * vsize;
1033 for (int i = 0; i < 4; ++i) {
1034 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1035 }
1036
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001037 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001038
1039 target->drawIndexed(kTriangles_PrimitiveType, 0,
1040 0, 8, this->aaFillRectIndexCount());
1041}
1042
bsalomon@google.coma3108262011-10-10 14:08:47 +00001043void GrContext::strokeAARect(GrDrawTarget* target,
1044 const GrRect& devRect,
1045 const GrVec& devStrokeSize,
1046 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001047 const GrScalar& dx = devStrokeSize.fX;
1048 const GrScalar& dy = devStrokeSize.fY;
1049 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1050 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1051
bsalomon@google.com205d4602011-04-25 12:43:45 +00001052 GrScalar spare;
1053 {
1054 GrScalar w = devRect.width() - dx;
1055 GrScalar h = devRect.height() - dy;
1056 spare = GrMin(w, h);
1057 }
1058
1059 if (spare <= 0) {
1060 GrRect r(devRect);
1061 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001062 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001063 return;
1064 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001065 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001066 size_t vsize = GrDrawTarget::VertexSize(layout);
1067
1068 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001069 if (!geo.succeeded()) {
1070 GrPrintf("Failed to get space for vertices!\n");
1071 return;
1072 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001073 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1074 if (NULL == indexBuffer) {
1075 GrPrintf("Failed to create index buffer!\n");
1076 return;
1077 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001078
1079 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1080
1081 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1082 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1083 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1084 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1085
1086 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1087 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1088 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1089 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1090
1091 verts += sizeof(GrPoint);
1092 for (int i = 0; i < 4; ++i) {
1093 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1094 }
1095
bsalomon@google.coma3108262011-10-10 14:08:47 +00001096 GrColor innerColor;
1097 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001098 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001099 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001100 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001101 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001102 verts += 4 * vsize;
1103 for (int i = 0; i < 8; ++i) {
1104 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1105 }
1106
1107 verts += 8 * vsize;
1108 for (int i = 0; i < 8; ++i) {
1109 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1110 }
1111
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001112 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001113 target->drawIndexed(kTriangles_PrimitiveType,
1114 0, 0, 16, aaStrokeRectIndexCount());
1115}
1116
reed@google.com20efde72011-05-09 17:00:02 +00001117/**
1118 * Returns true if the rects edges are integer-aligned.
1119 */
1120static bool isIRect(const GrRect& r) {
1121 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1122 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1123}
1124
bsalomon@google.com205d4602011-04-25 12:43:45 +00001125static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001126 const GrRect& rect,
1127 GrScalar width,
1128 const GrMatrix* matrix,
1129 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001130 GrRect* devRect,
1131 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001132 // we use a simple coverage ramp to do aa on axis-aligned rects
1133 // we check if the rect will be axis-aligned, and the rect won't land on
1134 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001135
bsalomon@google.coma3108262011-10-10 14:08:47 +00001136 // we are keeping around the "tweak the alpha" trick because
1137 // it is our only hope for the fixed-pipe implementation.
1138 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001139 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001140 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001141 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001142 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001143#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001144 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001145#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001146 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001147 } else {
1148 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001149 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001150 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001151 const GrDrawState& drawState = target->getDrawState();
1152 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001153 return false;
1154 }
1155
bsalomon@google.com471d4712011-08-23 15:45:25 +00001156 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001157 return false;
1158 }
1159
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001160 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001161 return false;
1162 }
1163
1164 if (NULL != matrix &&
1165 !matrix->preservesAxisAlignment()) {
1166 return false;
1167 }
1168
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001169 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001170 if (NULL != matrix) {
1171 combinedMatrix->preConcat(*matrix);
1172 GrAssert(combinedMatrix->preservesAxisAlignment());
1173 }
1174
1175 combinedMatrix->mapRect(devRect, rect);
1176 devRect->sort();
1177
1178 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001179 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001180 } else {
1181 return true;
1182 }
1183}
1184
bsalomon@google.com27847de2011-02-22 20:59:41 +00001185void GrContext::drawRect(const GrPaint& paint,
1186 const GrRect& rect,
1187 GrScalar width,
1188 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001189 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001190
1191 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001192 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001193
bsalomon@google.com205d4602011-04-25 12:43:45 +00001194 GrRect devRect = rect;
1195 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001196 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001197 bool needAA = paint.fAntiAlias &&
1198 !this->getRenderTarget()->isMultisampled();
1199 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1200 &combinedMatrix, &devRect,
1201 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001202
1203 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001204 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001205 if (width >= 0) {
1206 GrVec strokeSize;;
1207 if (width > 0) {
1208 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001209 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001210 strokeSize.setAbs(strokeSize);
1211 } else {
1212 strokeSize.set(GR_Scalar1, GR_Scalar1);
1213 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001214 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001215 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001216 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001217 }
1218 return;
1219 }
1220
bsalomon@google.com27847de2011-02-22 20:59:41 +00001221 if (width >= 0) {
1222 // TODO: consider making static vertex buffers for these cases.
1223 // Hairline could be done by just adding closing vertex to
1224 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001225 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1226
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227 static const int worstCaseVertCount = 10;
1228 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1229
1230 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001231 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001232 return;
1233 }
1234
1235 GrPrimitiveType primType;
1236 int vertCount;
1237 GrPoint* vertex = geo.positions();
1238
1239 if (width > 0) {
1240 vertCount = 10;
1241 primType = kTriangleStrip_PrimitiveType;
1242 setStrokeRectStrip(vertex, rect, width);
1243 } else {
1244 // hairline
1245 vertCount = 5;
1246 primType = kLineStrip_PrimitiveType;
1247 vertex[0].set(rect.fLeft, rect.fTop);
1248 vertex[1].set(rect.fRight, rect.fTop);
1249 vertex[2].set(rect.fRight, rect.fBottom);
1250 vertex[3].set(rect.fLeft, rect.fBottom);
1251 vertex[4].set(rect.fLeft, rect.fTop);
1252 }
1253
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001254 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001256 GrDrawState* drawState = target->drawState();
1257 avmr.set(drawState);
1258 drawState->preConcatViewMatrix(*matrix);
1259 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001260 }
1261
1262 target->drawNonIndexed(primType, 0, vertCount);
1263 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001264#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001265 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001266 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1267 if (NULL == sqVB) {
1268 GrPrintf("Failed to create static rect vb.\n");
1269 return;
1270 }
1271 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001272 GrDrawState* drawState = target->drawState();
1273 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001274 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001275 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001276 0, rect.height(), rect.fTop,
1277 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001278
1279 if (NULL != matrix) {
1280 m.postConcat(*matrix);
1281 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001282 drawState->preConcatViewMatrix(m);
1283 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001284
bsalomon@google.com27847de2011-02-22 20:59:41 +00001285 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001286#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001287 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001288#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001289 }
1290}
1291
1292void GrContext::drawRectToRect(const GrPaint& paint,
1293 const GrRect& dstRect,
1294 const GrRect& srcRect,
1295 const GrMatrix* dstMatrix,
1296 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001297 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001299 // srcRect refers to paint's first texture
1300 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001301 drawRect(paint, dstRect, -1, dstMatrix);
1302 return;
1303 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001304
bsalomon@google.com27847de2011-02-22 20:59:41 +00001305 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1306
1307#if GR_STATIC_RECT_VB
1308 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001309 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001310 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001311 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001312
1313 GrMatrix m;
1314
1315 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1316 0, dstRect.height(), dstRect.fTop,
1317 0, 0, GrMatrix::I()[8]);
1318 if (NULL != dstMatrix) {
1319 m.postConcat(*dstMatrix);
1320 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001321 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001322
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001323 // srcRect refers to first stage
1324 int otherStageMask = paint.getActiveStageMask() &
1325 (~(1 << GrPaint::kFirstTextureStage));
1326 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001327 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001328 }
1329
bsalomon@google.com27847de2011-02-22 20:59:41 +00001330 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1331 0, srcRect.height(), srcRect.fTop,
1332 0, 0, GrMatrix::I()[8]);
1333 if (NULL != srcMatrix) {
1334 m.postConcat(*srcMatrix);
1335 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001336 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001337
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001338 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1339 if (NULL == sqVB) {
1340 GrPrintf("Failed to create static rect vb.\n");
1341 return;
1342 }
1343 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1345#else
1346
1347 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001348#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001349 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001350#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001351 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1352#endif
1353
tomhudson@google.com93813632011-10-27 20:21:16 +00001354 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1355 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001356 srcRects[0] = &srcRect;
1357 srcMatrices[0] = srcMatrix;
1358
1359 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1360#endif
1361}
1362
1363void GrContext::drawVertices(const GrPaint& paint,
1364 GrPrimitiveType primitiveType,
1365 int vertexCount,
1366 const GrPoint positions[],
1367 const GrPoint texCoords[],
1368 const GrColor colors[],
1369 const uint16_t indices[],
1370 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001371 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372
1373 GrDrawTarget::AutoReleaseGeometry geo;
1374
1375 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1376
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001377 bool hasTexCoords[GrPaint::kTotalStages] = {
1378 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1379 0 // remaining stages use positions
1380 };
1381
1382 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001383
1384 if (NULL != colors) {
1385 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001386 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001387 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001388
1389 if (sizeof(GrPoint) != vertexSize) {
1390 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001391 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001392 return;
1393 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001394 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001396 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1397 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001398 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001399 NULL,
1400 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001401 void* curVertex = geo.vertices();
1402
1403 for (int i = 0; i < vertexCount; ++i) {
1404 *((GrPoint*)curVertex) = positions[i];
1405
1406 if (texOffsets[0] > 0) {
1407 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1408 }
1409 if (colorOffset > 0) {
1410 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1411 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001412 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001413 }
1414 } else {
1415 target->setVertexSourceToArray(layout, positions, vertexCount);
1416 }
1417
bsalomon@google.com91958362011-06-13 17:58:13 +00001418 // we don't currently apply offscreen AA to this path. Need improved
1419 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001420
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001421 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001422 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001423 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001424 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001425 target->drawNonIndexed(primitiveType, 0, vertexCount);
1426 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001427}
1428
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001429///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001430#include "SkDraw.h"
1431#include "SkRasterClip.h"
1432
1433namespace {
1434
1435SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1436 switch (fill) {
1437 case kWinding_PathFill:
1438 return SkPath::kWinding_FillType;
1439 case kEvenOdd_PathFill:
1440 return SkPath::kEvenOdd_FillType;
1441 case kInverseWinding_PathFill:
1442 return SkPath::kInverseWinding_FillType;
1443 case kInverseEvenOdd_PathFill:
1444 return SkPath::kInverseEvenOdd_FillType;
1445 default:
1446 GrCrash("Unexpected fill.");
1447 return SkPath::kWinding_FillType;
1448 }
1449}
1450
1451// gets device coord bounds of path (not considering the fill) and clip. The
1452// path bounds will be a subset of the clip bounds. returns false if path bounds
1453// would be empty.
1454bool get_path_and_clip_bounds(const GrDrawTarget* target,
1455 const GrPath& path,
1456 const GrVec* translate,
1457 GrIRect* pathBounds,
1458 GrIRect* clipBounds) {
1459 // compute bounds as intersection of rt size, clip, and path
1460 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1461 if (NULL == rt) {
1462 return false;
1463 }
1464 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1465 const GrClip& clip = target->getClip();
1466 if (clip.hasConservativeBounds()) {
1467 clip.getConservativeBounds().roundOut(clipBounds);
1468 if (!pathBounds->intersect(*clipBounds)) {
1469 return false;
1470 }
1471 } else {
1472 // pathBounds is currently the rt extent, set clip bounds to that rect.
1473 *clipBounds = *pathBounds;
1474 }
1475 GrRect pathSBounds = path.getBounds();
1476 if (!pathSBounds.isEmpty()) {
1477 if (NULL != translate) {
1478 pathSBounds.offset(*translate);
1479 }
1480 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1481 pathSBounds);
1482 GrIRect pathIBounds;
1483 pathSBounds.roundOut(&pathIBounds);
1484 if (!pathBounds->intersect(pathIBounds)) {
1485 return false;
1486 }
1487 } else {
1488 return false;
1489 }
1490 return true;
1491}
1492
1493/**
1494 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1495 * scratch texture.
1496 */
1497
1498bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1499 const GrIRect& pathDevBounds,
1500 GrPathFill fill,
1501 GrContext* context,
1502 const GrPoint* translate,
1503 GrAutoScratchTexture* tex) {
1504 SkPaint paint;
1505 SkPath tmpPath;
1506 const SkPath* pathToDraw = &clientPath;
1507 if (kHairLine_PathFill == fill) {
1508 paint.setStyle(SkPaint::kStroke_Style);
1509 paint.setStrokeWidth(SK_Scalar1);
1510 } else {
1511 paint.setStyle(SkPaint::kFill_Style);
1512 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1513 if (skfill != pathToDraw->getFillType()) {
1514 tmpPath = *pathToDraw;
1515 tmpPath.setFillType(skfill);
1516 pathToDraw = &tmpPath;
1517 }
1518 }
1519 paint.setAntiAlias(true);
1520 paint.setColor(SK_ColorWHITE);
1521
1522 GrMatrix matrix = context->getMatrix();
1523 if (NULL != translate) {
1524 matrix.postTranslate(translate->fX, translate->fY);
1525 }
1526
1527 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1528 -pathDevBounds.fTop * SK_Scalar1);
1529 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1530 pathDevBounds.height());
1531
1532 SkBitmap bm;
1533 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1534 if (!bm.allocPixels()) {
1535 return false;
1536 }
1537 sk_bzero(bm.getPixels(), bm.getSafeSize());
1538
1539 SkDraw draw;
1540 sk_bzero(&draw, sizeof(draw));
1541 SkRasterClip rc(bounds);
1542 draw.fRC = &rc;
1543 draw.fClip = &rc.bwRgn();
1544 draw.fMatrix = &matrix;
1545 draw.fBitmap = &bm;
1546 draw.drawPath(*pathToDraw, paint);
1547
1548 const GrTextureDesc desc = {
1549 kNone_GrTextureFlags,
1550 kNone_GrAALevel,
1551 bounds.fRight,
1552 bounds.fBottom,
1553 kAlpha_8_GrPixelConfig
1554 };
1555
1556 tex->set(context, desc);
1557 GrTexture* texture = tex->texture();
1558
1559 if (NULL == texture) {
1560 return false;
1561 }
1562 SkAutoLockPixels alp(bm);
1563 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1564 bm.getPixels(), bm.rowBytes());
1565 return true;
1566}
1567
1568void draw_around_inv_path(GrDrawTarget* target,
1569 GrDrawState::StageMask stageMask,
1570 const GrIRect& clipBounds,
1571 const GrIRect& pathBounds) {
1572 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1573 GrRect rect;
1574 if (clipBounds.fTop < pathBounds.fTop) {
1575 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1576 clipBounds.fRight, pathBounds.fTop);
1577 target->drawSimpleRect(rect, NULL, stageMask);
1578 }
1579 if (clipBounds.fLeft < pathBounds.fLeft) {
1580 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1581 pathBounds.fLeft, pathBounds.fBottom);
1582 target->drawSimpleRect(rect, NULL, stageMask);
1583 }
1584 if (clipBounds.fRight > pathBounds.fRight) {
1585 rect.iset(pathBounds.fRight, pathBounds.fTop,
1586 clipBounds.fRight, pathBounds.fBottom);
1587 target->drawSimpleRect(rect, NULL, stageMask);
1588 }
1589 if (clipBounds.fBottom > pathBounds.fBottom) {
1590 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1591 clipBounds.fRight, clipBounds.fBottom);
1592 target->drawSimpleRect(rect, NULL, stageMask);
1593 }
1594}
1595
1596}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001597
reed@google.com07f3ee12011-05-16 17:21:57 +00001598void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1599 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001600
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001601 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001602 if (GrIsFillInverted(fill)) {
1603 this->drawPaint(paint);
1604 }
1605 return;
1606 }
1607
bsalomon@google.com27847de2011-02-22 20:59:41 +00001608 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001609 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001610
bsalomon@google.com289533a2011-10-27 12:34:25 +00001611 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1612
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001613 // An Assumption here is that path renderer would use some form of tweaking
1614 // the src color (either the input alpha or in the frag shader) to implement
1615 // aa. If we have some future driver-mojo path AA that can do the right
1616 // thing WRT to the blend then we'll need some query on the PR.
1617 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001618#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001619 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001620#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001621 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001622 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001623
1624 bool doOSAA = false;
1625 GrPathRenderer* pr = NULL;
1626 if (prAA) {
1627 pr = this->getPathRenderer(path, fill, true);
1628 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001629 GrAutoScratchTexture ast;
1630 GrIRect pathBounds, clipBounds;
1631 if (!get_path_and_clip_bounds(target, path, translate,
1632 &pathBounds, &clipBounds)) {
1633 return;
1634 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001635 prAA = false;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001636 if (this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
1637 pr = this->getPathRenderer(path, fill, false);
1638 doOSAA = true;
1639 }
1640 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1641 fill, this,
1642 translate, &ast)) {
1643 GrTexture* texture = ast.texture();
1644 GrAssert(NULL != texture);
1645 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1646 enum {
1647 kPathMaskStage = GrPaint::kTotalStages,
1648 };
1649 target->drawState()->setTexture(kPathMaskStage, texture);
1650 target->drawState()->sampler(kPathMaskStage)->reset();
1651 GrScalar w = GrIntToScalar(pathBounds.width());
1652 GrScalar h = GrIntToScalar(pathBounds.height());
1653 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1654 h / texture->height());
1655 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1656 srcRects[kPathMaskStage] = &maskRect;
1657 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001658 GrRect dstRect = GrRect::MakeLTRB(
1659 SK_Scalar1* pathBounds.fLeft,
1660 SK_Scalar1* pathBounds.fTop,
1661 SK_Scalar1* pathBounds.fRight,
1662 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001663 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1664 target->drawState()->setTexture(kPathMaskStage, NULL);
1665 if (GrIsFillInverted(fill)) {
1666 draw_around_inv_path(target, stageMask,
1667 clipBounds, pathBounds);
1668 }
1669 return;
1670 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001671 }
1672 } else {
1673 pr = this->getPathRenderer(path, fill, false);
1674 }
1675
bsalomon@google.com30085192011-08-19 15:42:31 +00001676 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001677#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001678 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001679#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001680 return;
1681 }
1682
bsalomon@google.com289533a2011-10-27 12:34:25 +00001683 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001684
bsalomon@google.com289533a2011-10-27 12:34:25 +00001685 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001686 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001687 GrIRect pathBounds;
1688 GrIRect clipBounds;
1689 if (!get_path_and_clip_bounds(target, path, translate,
1690 &pathBounds, &clipBounds)) {
1691 return;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001692 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001693 OffscreenRecord record;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001694 if (this->prepareForOffscreenAA(target, needsStencil, pathBounds,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001695 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001696 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1697 for (int ty = 0; ty < record.fTileCountY; ++ty) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001698 this->setupOffscreenAAPass1(target, pathBounds,
1699 tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001700 pr->drawPath(0);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001701 this->doOffscreenAAPass2(target, paint, pathBounds,
1702 tx, ty, &record);
bsalomon@google.com91958362011-06-13 17:58:13 +00001703 }
1704 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001705 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001706 if (GrIsFillInverted(fill)) {
1707 draw_around_inv_path(target, stageMask, clipBounds, pathBounds);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001708 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001709 return;
1710 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001711 }
1712 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001713}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001714
bsalomon@google.com27847de2011-02-22 20:59:41 +00001715////////////////////////////////////////////////////////////////////////////////
1716
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001717void GrContext::flush(int flagsBitfield) {
1718 if (kDiscard_FlushBit & flagsBitfield) {
1719 fDrawBuffer->reset();
1720 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001721 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001722 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001723 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001724 fGpu->forceRenderTargetFlush();
1725 }
1726}
1727
1728void GrContext::flushText() {
1729 if (kText_DrawCategory == fLastDrawCategory) {
1730 flushDrawBuffer();
1731 }
1732}
1733
1734void GrContext::flushDrawBuffer() {
1735#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001736 if (fDrawBuffer) {
1737 fDrawBuffer->playback(fGpu);
1738 fDrawBuffer->reset();
1739 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001740#endif
1741}
1742
bsalomon@google.com6f379512011-11-16 20:36:03 +00001743void GrContext::internalWriteTexturePixels(GrTexture* texture,
1744 int left, int top,
1745 int width, int height,
1746 GrPixelConfig config,
1747 const void* buffer,
1748 size_t rowBytes,
1749 uint32_t flags) {
1750 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001751 ASSERT_OWNED_RESOURCE(texture);
1752
bsalomon@google.com6f379512011-11-16 20:36:03 +00001753 if (!(kDontFlush_PixelOpsFlag & flags)) {
1754 this->flush();
1755 }
1756 // TODO: use scratch texture to perform conversion
1757 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1758 GrPixelConfigIsUnpremultiplied(config)) {
1759 return;
1760 }
1761
1762 fGpu->writeTexturePixels(texture, left, top, width, height,
1763 config, buffer, rowBytes);
1764}
1765
1766bool GrContext::internalReadTexturePixels(GrTexture* texture,
1767 int left, int top,
1768 int width, int height,
1769 GrPixelConfig config,
1770 void* buffer,
1771 size_t rowBytes,
1772 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001773 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001774 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001775
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001776 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001777 GrRenderTarget* target = texture->asRenderTarget();
1778 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001779 return this->internalReadRenderTargetPixels(target,
1780 left, top, width, height,
1781 config, buffer, rowBytes,
1782 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001783 } else {
1784 return false;
1785 }
1786}
1787
bsalomon@google.com6f379512011-11-16 20:36:03 +00001788bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1789 int left, int top,
1790 int width, int height,
1791 GrPixelConfig config,
1792 void* buffer,
1793 size_t rowBytes,
1794 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001795 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001796 ASSERT_OWNED_RESOURCE(target);
1797
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001798 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001799 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001800 if (NULL == target) {
1801 return false;
1802 }
1803 }
1804
1805 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1806 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1807 // not supported at this time.
1808 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1809 !GrPixelConfigIsUnpremultiplied(config)) {
1810 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001811 }
1812
bsalomon@google.com6f379512011-11-16 20:36:03 +00001813 if (!(kDontFlush_PixelOpsFlag & flags)) {
1814 this->flush();
1815 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001816
1817 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001818 bool swapRAndB = NULL != src &&
1819 fGpu->preferredReadPixelsConfig(config) ==
1820 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001821
1822 bool flipY = NULL != src &&
1823 fGpu->readPixelsWillPayForYFlip(target, left, top,
1824 width, height, config,
1825 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001826 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1827 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001828
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001829 if (NULL == src && alphaConversion) {
1830 // we should fallback to cpu conversion here. This could happen when
1831 // we were given an external render target by the client that is not
1832 // also a texture (e.g. FBO 0 in GL)
1833 return false;
1834 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001835 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001836 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001837 if (flipY || swapRAndB || alphaConversion) {
1838 GrAssert(NULL != src);
1839 if (swapRAndB) {
1840 config = GrPixelConfigSwapRAndB(config);
1841 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001842 }
1843 // Make the scratch a render target because we don't have a robust
1844 // readTexturePixels as of yet (it calls this function).
1845 const GrTextureDesc desc = {
1846 kRenderTarget_GrTextureFlagBit,
1847 kNone_GrAALevel,
1848 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001849 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001850 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001851
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001852 // When a full readback is faster than a partial we could always make
1853 // the scratch exactly match the passed rect. However, if we see many
1854 // different size rectangles we will trash our texture cache and pay the
1855 // cost of creating and destroying many textures. So, we only request
1856 // an exact match when the caller is reading an entire RT.
1857 ScratchTexMatch match = kApprox_ScratchTexMatch;
1858 if (0 == left &&
1859 0 == top &&
1860 target->width() == width &&
1861 target->height() == height &&
1862 fGpu->fullReadPixelsIsFasterThanPartial()) {
1863 match = kExact_ScratchTexMatch;
1864 }
1865 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001866 GrTexture* texture = ast.texture();
1867 if (!texture) {
1868 return false;
1869 }
1870 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001871 GrAssert(NULL != target);
1872
1873 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001874 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001875 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001876 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001877
bsalomon@google.comc4364992011-11-07 15:54:49 +00001878 GrMatrix matrix;
1879 if (flipY) {
1880 matrix.setTranslate(SK_Scalar1 * left,
1881 SK_Scalar1 * (top + height));
1882 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1883 } else {
1884 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1885 }
1886 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001887 drawState->sampler(0)->reset(matrix);
1888 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001889 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001890 GrRect rect;
1891 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1892 fGpu->drawSimpleRect(rect, NULL, 0x1);
1893 left = 0;
1894 top = 0;
1895 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001896 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001897 left, top, width, height,
1898 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001899}
1900
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001901void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1902 if (NULL == src || NULL == dst) {
1903 return;
1904 }
1905 ASSERT_OWNED_RESOURCE(src);
1906
1907 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001908 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001909 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001910 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001911 GrMatrix sampleM;
1912 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001913 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001914 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001915 SkRect rect = SkRect::MakeXYWH(0, 0,
1916 SK_Scalar1 * src->width(),
1917 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001918 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1919}
1920
bsalomon@google.com6f379512011-11-16 20:36:03 +00001921void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1922 int left, int top,
1923 int width, int height,
1924 GrPixelConfig config,
1925 const void* buffer,
1926 size_t rowBytes,
1927 uint32_t flags) {
1928 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001929 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001930
1931 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001932 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001933 if (NULL == target) {
1934 return;
1935 }
1936 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001937
1938 // TODO: when underlying api has a direct way to do this we should use it
1939 // (e.g. glDrawPixels on desktop GL).
1940
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001941 // If the RT is also a texture and we don't have to do PM/UPM conversion
1942 // then take the texture path, which we expect to be at least as fast or
1943 // faster since it doesn't use an intermediate texture as we do below.
1944
1945#if !GR_MAC_BUILD
1946 // At least some drivers on the Mac get confused when glTexImage2D is called
1947 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1948 // determine what OS versions and/or HW is affected.
1949 if (NULL != target->asTexture() &&
1950 GrPixelConfigIsUnpremultiplied(target->config()) ==
1951 GrPixelConfigIsUnpremultiplied(config)) {
1952
1953 this->internalWriteTexturePixels(target->asTexture(),
1954 left, top, width, height,
1955 config, buffer, rowBytes, flags);
1956 return;
1957 }
1958#endif
1959
1960 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1961 GrPixelConfigSwapRAndB(config);
1962 if (swapRAndB) {
1963 config = GrPixelConfigSwapRAndB(config);
1964 }
1965
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001966 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001967 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001968 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001969 GrAutoScratchTexture ast(this, desc);
1970 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001971 if (NULL == texture) {
1972 return;
1973 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001974 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1975 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001976
bsalomon@google.com27847de2011-02-22 20:59:41 +00001977 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001978 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001979 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001980
1981 GrMatrix matrix;
1982 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001983 drawState->setViewMatrix(matrix);
1984 drawState->setRenderTarget(target);
1985 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001986
bsalomon@google.com5c638652011-07-18 19:31:59 +00001987 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001988 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1989 GrSamplerState::kNearest_Filter,
1990 matrix);
1991 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001992
1993 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1994 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001995 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001996 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1997 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001998 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001999 return;
2000 }
2001 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
2002 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
2003}
2004////////////////////////////////////////////////////////////////////////////////
2005
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002006void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002007 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002008
2009 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
2010 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002011 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002012 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002013 if (paint.getTexture(i)) {
2014 *drawState->sampler(s) = paint.getTextureSampler(i);
2015 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002016 }
2017
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002018 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002019
2020 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
2021 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002022 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002023 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002024 if (paint.getMask(i)) {
2025 *drawState->sampler(s) = paint.getMaskSampler(i);
2026 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002027 }
2028
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002029 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002030
2031 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002032 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002033 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002034 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002035 }
2036 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002037 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002038 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002039 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002040 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002041 if (paint.fColorMatrixEnabled) {
2042 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
2043 } else {
2044 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
2045 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002046 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002047 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002048 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comdd1be602012-01-18 20:34:00 +00002049 drawState->setCoverage(paint.fCoverage);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00002050
2051 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
2052 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
2053 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002054}
2055
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002056GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002057 DrawCategory category) {
2058 if (category != fLastDrawCategory) {
2059 flushDrawBuffer();
2060 fLastDrawCategory = category;
2061 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002062 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002063 GrDrawTarget* target = fGpu;
2064 switch (category) {
2065 case kText_DrawCategory:
2066#if DEFER_TEXT_RENDERING
2067 target = fDrawBuffer;
2068 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2069#else
2070 target = fGpu;
2071#endif
2072 break;
2073 case kUnbuffered_DrawCategory:
2074 target = fGpu;
2075 break;
2076 case kBuffered_DrawCategory:
2077 target = fDrawBuffer;
2078 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2079 break;
2080 }
2081 return target;
2082}
2083
bsalomon@google.com289533a2011-10-27 12:34:25 +00002084GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
2085 GrPathFill fill,
2086 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00002087 if (NULL == fPathRendererChain) {
2088 fPathRendererChain =
2089 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
2090 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00002091 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
2092 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00002093}
2094
bsalomon@google.com27847de2011-02-22 20:59:41 +00002095////////////////////////////////////////////////////////////////////////////////
2096
bsalomon@google.com27847de2011-02-22 20:59:41 +00002097void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002098 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002099 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002100 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002101}
2102
2103GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002104 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002105}
2106
2107const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002108 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002109}
2110
2111const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002112 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002113}
2114
2115void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002116 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002117}
2118
2119void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002120 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002121}
2122
2123static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2124 intptr_t mask = 1 << shift;
2125 if (pred) {
2126 bits |= mask;
2127 } else {
2128 bits &= ~mask;
2129 }
2130 return bits;
2131}
2132
2133void GrContext::resetStats() {
2134 fGpu->resetStats();
2135}
2136
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002137const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002138 return fGpu->getStats();
2139}
2140
2141void GrContext::printStats() const {
2142 fGpu->printStats();
2143}
2144
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002145GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002146 fGpu = gpu;
2147 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002148 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002149
bsalomon@google.com30085192011-08-19 15:42:31 +00002150 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002151
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002152 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2153 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002154 fFontCache = new GrFontCache(fGpu);
2155
2156 fLastDrawCategory = kUnbuffered_DrawCategory;
2157
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002158 fDrawBuffer = NULL;
2159 fDrawBufferVBAllocPool = NULL;
2160 fDrawBufferIBAllocPool = NULL;
2161
bsalomon@google.com205d4602011-04-25 12:43:45 +00002162 fAAFillRectIndexBuffer = NULL;
2163 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002164
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002165 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2166 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002167 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2168 }
2169 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002170
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002171 this->setupDrawBuffer();
2172}
2173
2174void GrContext::setupDrawBuffer() {
2175
2176 GrAssert(NULL == fDrawBuffer);
2177 GrAssert(NULL == fDrawBufferVBAllocPool);
2178 GrAssert(NULL == fDrawBufferIBAllocPool);
2179
bsalomon@google.com27847de2011-02-22 20:59:41 +00002180#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002181 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002182 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002183 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2184 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002185 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002186 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002187 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002188 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2189
bsalomon@google.com471d4712011-08-23 15:45:25 +00002190 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2191 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002192 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002193#endif
2194
2195#if BATCH_RECT_TO_RECT
2196 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2197#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002198}
2199
bsalomon@google.com27847de2011-02-22 20:59:41 +00002200GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2201 GrDrawTarget* target;
2202#if DEFER_TEXT_RENDERING
2203 target = prepareToDraw(paint, kText_DrawCategory);
2204#else
2205 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2206#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002207 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002208 return target;
2209}
2210
2211const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2212 return fGpu->getQuadIndexBuffer();
2213}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002214
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002215void GrContext::convolveInX(GrTexture* texture,
2216 const SkRect& rect,
2217 const float* kernel,
2218 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002219 ASSERT_OWNED_RESOURCE(texture);
2220
bsalomon@google.com99621082011-11-15 16:47:16 +00002221 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002222 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2223}
2224
2225void GrContext::convolveInY(GrTexture* texture,
2226 const SkRect& rect,
2227 const float* kernel,
2228 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002229 ASSERT_OWNED_RESOURCE(texture);
2230
bsalomon@google.com99621082011-11-15 16:47:16 +00002231 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002232 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2233}
2234
2235void GrContext::convolve(GrTexture* texture,
2236 const SkRect& rect,
2237 float imageIncrement[2],
2238 const float* kernel,
2239 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002240 ASSERT_OWNED_RESOURCE(texture);
2241
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002242 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002243 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.comdd1be602012-01-18 20:34:00 +00002244 GrRenderTarget* target = drawState->getRenderTarget();
2245 drawState->reset();
2246 drawState->setRenderTarget(target);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002247 GrMatrix sampleM;
2248 sampleM.setIDiv(texture->width(), texture->height());
2249 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2250 GrSamplerState::kConvolution_Filter,
2251 sampleM);
2252 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2253 kernel,
2254 imageIncrement);
2255
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002256 drawState->setTexture(0, texture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002257 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2258}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002259
2260///////////////////////////////////////////////////////////////////////////////