blob: dd1b2768063fc5f45dc814a28b02798c28e45dc7 [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,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000170 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000171 bool scratch,
172 uint32_t v[4]) {
173 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
174 // we assume we only need 16 bits of width and height
175 // assert that texture creation will fail anyway if this assumption
176 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000177 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000178 v[0] = clientKey & 0xffffffffUL;
179 v[1] = (clientKey >> 32) & 0xffffffffUL;
180 v[2] = width | (height << 16);
181
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000182 v[3] = (sampleCnt << 24);
183 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
184
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000185 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000186 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
187
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000188 bool tiled = NULL != sampler &&
189 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
190 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000191
192 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000194 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000195 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000196 }
197 }
198 }
199
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000200 if (scratch) {
201 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000202 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000203
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000204 v[3] |= kTextureBit;
205
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000206 return v[3] & kNPOTBit;
207}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000208
209// we should never have more than one stencil buffer with same combo of
210// (width,height,samplecount)
211void gen_stencil_key_values(int width, int height,
212 int sampleCnt, uint32_t v[4]) {
213 v[0] = width;
214 v[1] = height;
215 v[2] = sampleCnt;
216 v[3] = kStencilBufferBit;
217}
218
219void gen_stencil_key_values(const GrStencilBuffer* sb,
220 uint32_t v[4]) {
221 gen_stencil_key_values(sb->width(), sb->height(),
222 sb->numSamples(), v);
223}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000224
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000225}
226
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000227GrContext::TextureCacheEntry GrContext::findAndLockTexture(
228 TextureKey key,
229 int width,
230 int height,
231 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000232 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000233 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000234 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000235 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
236 GrResourceCache::kNested_LockType));
237}
238
bsalomon@google.comfb309512011-11-30 14:13:48 +0000239bool GrContext::isTextureInCache(TextureKey key,
240 int width,
241 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000242 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000243 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000244 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000245 GrResourceKey resourceKey(v);
246 return fTextureCache->hasKey(resourceKey);
247}
248
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000249GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000250 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000251 uint32_t v[4];
252 gen_stencil_key_values(sb, v);
253 GrResourceKey resourceKey(v);
254 return fTextureCache->createAndLock(resourceKey, sb);
255}
256
257GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
258 int sampleCnt) {
259 uint32_t v[4];
260 gen_stencil_key_values(width, height, sampleCnt, v);
261 GrResourceKey resourceKey(v);
262 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
263 GrResourceCache::kSingle_LockType);
264 if (NULL != entry) {
265 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
266 return sb;
267 } else {
268 return NULL;
269 }
270}
271
272void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000273 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000274 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000275}
276
277static void stretchImage(void* dst,
278 int dstW,
279 int dstH,
280 void* src,
281 int srcW,
282 int srcH,
283 int bpp) {
284 GrFixed dx = (srcW << 16) / dstW;
285 GrFixed dy = (srcH << 16) / dstH;
286
287 GrFixed y = dy >> 1;
288
289 int dstXLimit = dstW*bpp;
290 for (int j = 0; j < dstH; ++j) {
291 GrFixed x = dx >> 1;
292 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
293 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
294 for (int i = 0; i < dstXLimit; i += bpp) {
295 memcpy((uint8_t*) dstRow + i,
296 (uint8_t*) srcRow + (x>>16)*bpp,
297 bpp);
298 x += dx;
299 }
300 y += dy;
301 }
302}
303
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000304GrContext::TextureCacheEntry GrContext::createAndLockTexture(
305 TextureKey key,
306 const GrSamplerState* sampler,
307 const GrTextureDesc& desc,
308 void* srcData,
309 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000310 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000311
312#if GR_DUMP_TEXTURE_UPLOAD
313 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
314#endif
315
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000316 TextureCacheEntry entry;
317 uint32_t v[4];
318 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000319 desc.fWidth, desc.fHeight,
320 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000321 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000322
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000323 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000324 GrAssert(NULL != sampler);
325 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
326 desc.fWidth,
327 desc.fHeight,
328 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000329
330 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000331 clampEntry = this->createAndLockTexture(key, NULL, desc,
332 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000333 GrAssert(NULL != clampEntry.texture());
334 if (NULL == clampEntry.texture()) {
335 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000336 }
337 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000338 GrTextureDesc rtDesc = desc;
339 rtDesc.fFlags = rtDesc.fFlags |
340 kRenderTarget_GrTextureFlagBit |
341 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000342 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
343 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000344
345 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
346
347 if (NULL != texture) {
348 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000349 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000350 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000351 drawState->setRenderTarget(texture->asRenderTarget());
352 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000353
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000354 GrSamplerState::Filter filter;
355 // if filtering is not desired then we want to ensure all
356 // texels in the resampled image are copies of texels from
357 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000358 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000359 filter = GrSamplerState::kNearest_Filter;
360 } else {
361 filter = GrSamplerState::kBilinear_Filter;
362 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000363 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
364 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000365
366 static const GrVertexLayout layout =
367 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
368 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
369
370 if (arg.succeeded()) {
371 GrPoint* verts = (GrPoint*) arg.vertices();
372 verts[0].setIRectFan(0, 0,
373 texture->width(),
374 texture->height(),
375 2*sizeof(GrPoint));
376 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
377 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
378 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000379 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000380 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000381 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000382 } else {
383 // TODO: Our CPU stretch doesn't filter. But we create separate
384 // stretched textures when the sampler state is either filtered or
385 // not. Either implement filtered stretch blit on CPU or just create
386 // one when FBO case fails.
387
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000388 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389 // no longer need to clamp at min RT size.
390 rtDesc.fWidth = GrNextPow2(desc.fWidth);
391 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000392 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000393 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000394 rtDesc.fWidth *
395 rtDesc.fHeight);
396 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
397 srcData, desc.fWidth, desc.fHeight, bpp);
398
399 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
400
401 GrTexture* texture = fGpu->createTexture(rtDesc,
402 stretchedPixels.get(),
403 stretchedRowBytes);
404 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000405 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000406 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000407 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000408
409 } else {
410 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
411 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000413 }
414 }
415 return entry;
416}
417
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000418namespace {
419inline void gen_scratch_tex_key_values(const GrGpu* gpu,
420 const GrTextureDesc& desc,
421 uint32_t v[4]) {
422 // Instead of a client-provided key of the texture contents
423 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000424 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000425 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000426 // this code path isn't friendly to tiling with NPOT restricitons
427 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000428 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000429 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000430}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000431}
432
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000433GrContext::TextureCacheEntry GrContext::lockScratchTexture(
434 const GrTextureDesc& inDesc,
435 ScratchTexMatch match) {
436
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000437 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000438 if (kExact_ScratchTexMatch != match) {
439 // bin by pow2 with a reasonable min
440 static const int MIN_SIZE = 256;
441 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
442 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
443 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000444
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.com78d6cf92012-01-30 18:09:31 +0000716 // 16 samples matches what the skia sw rasterizer uses. (There is no
717 // accessible constant to reference from sw code).
718 desc.fSampleCnt = 16;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000719 } else {
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000720 record->fDownsample = OffscreenRecord::k4x4SinglePass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000721 record->fScale = OFFSCREEN_SSAA_SCALE;
722 // both downsample paths assume this
723 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000724 desc.fSampleCnt = 0;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000725 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000726
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000727 desc.fWidth *= record->fScale;
728 desc.fHeight *= record->fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000729 record->fOffscreen.set(this, desc);
730 if (NULL == record->fOffscreen.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000731 return false;
732 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000733 // the approximate lookup might have given us some slop space, might as well
734 // use it when computing the tiles size.
735 // these are scale values, will adjust after considering
736 // the possible second offscreen.
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000737 record->fTileSizeX = record->fOffscreen.texture()->width();
738 record->fTileSizeY = record->fOffscreen.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000739
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000740 record->fTileSizeX /= record->fScale;
741 record->fTileSizeY /= record->fScale;
742
743 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
744 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
745
tomhudson@google.com237a4612011-07-19 15:44:00 +0000746 record->fClip = target->getClip();
747
bsalomon@google.com91958362011-06-13 17:58:13 +0000748 target->saveCurrentDrawState(&record->fSavedState);
749 return true;
750}
751
752void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
753 const GrIRect& boundRect,
754 int tileX, int tileY,
755 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000756
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000757 GrRenderTarget* offRT = record->fOffscreen.texture()->asRenderTarget();
758 GrAssert(NULL != offRT);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000759
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000760 GrDrawState* drawState = target->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000761 GrMatrix vm = drawState->getViewMatrix();
762 drawState->reset();
763 *drawState->viewMatrix() = vm;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000764 drawState->setRenderTarget(offRT);
bsalomon@google.com46f7afb2012-01-18 19:51:55 +0000765
bsalomon@google.com289533a2011-10-27 12:34:25 +0000766#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com337af172012-01-11 16:00:42 +0000767 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000768#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000769
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000770 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000771 int left = boundRect.fLeft + tileX * record->fTileSizeX;
772 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000773 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000774 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000775 GrMatrix scaleM;
776 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000777 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000778
bsalomon@google.com91958362011-06-13 17:58:13 +0000779 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000780 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000781 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000782 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000783 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
784 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000785 target->setClip(GrClip(clear));
bsalomon@google.com46f7afb2012-01-18 19:51:55 +0000786 drawState->enableState(GrDrawState::kClip_StateBit);
787
bsalomon@google.com91958362011-06-13 17:58:13 +0000788#if 0
789 // visualize tile boundaries by setting edges of offscreen to white
790 // and interior to tranparent. black.
791 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000792
bsalomon@google.com91958362011-06-13 17:58:13 +0000793 static const int gOffset = 2;
794 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
795 record->fScale * w - gOffset,
796 record->fScale * h - gOffset);
797 target->clear(&clear2, 0x0);
798#else
799 target->clear(&clear, 0x0);
800#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000801}
802
bsalomon@google.com91958362011-06-13 17:58:13 +0000803void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000804 const GrPaint& paint,
805 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000806 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000807 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000808 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com46579e02012-01-11 18:51:15 +0000809 GrAssert(NULL != record->fOffscreen.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000810 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000811 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000812 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
813 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000814 tileRect.fRight = (tileX == record->fTileCountX-1) ?
815 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000816 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000817 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
818 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000819 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000820
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000821 GrSamplerState::Filter filter;
822 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
823 filter = GrSamplerState::k4x4Downsample_Filter;
824 } else {
825 filter = GrSamplerState::kBilinear_Filter;
826 }
827
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000828 GrTexture* src = record->fOffscreen.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000829 int scale;
830
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000831 enum {
832 kOffscreenStage = GrPaint::kTotalStages,
833 };
834
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000835 GrDrawState* drawState = target->drawState();
836
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000837 if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000838 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000839 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000840 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000841 } else {
842 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
843 record->fDownsample);
844 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000845 }
846
bsalomon@google.com91958362011-06-13 17:58:13 +0000847 // setup for draw back to main RT, we use the original
848 // draw state setup by the caller plus an additional coverage
849 // stage to handle the AA resolve. Also, we use an identity
850 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000851 int stageMask = paint.getActiveStageMask();
852
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000853 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000854 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000855
856 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000857 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000858 if (drawState->getViewInverse(&invVM)) {
859 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000860 }
861 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000862 // This is important when tiling, otherwise second tile's
863 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000864 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000865
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000866 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000867 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
868 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000869 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
870 scale * GR_Scalar1 / src->height());
871 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
872 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000873
reed@google.com20efde72011-05-09 17:00:02 +0000874 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000875 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000876 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000877 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000878}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000879
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000880void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
881 GrPathRenderer* pr,
882 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000883 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000884}
885
886////////////////////////////////////////////////////////////////////////////////
887
bsalomon@google.com27847de2011-02-22 20:59:41 +0000888/* create a triangle strip that strokes the specified triangle. There are 8
889 unique vertices, but we repreat the last 2 to close up. Alternatively we
890 could use an indices array, and then only send 8 verts, but not sure that
891 would be faster.
892 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000893static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000894 GrScalar width) {
895 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000896 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000897
898 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
899 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
900 verts[2].set(rect.fRight - rad, rect.fTop + rad);
901 verts[3].set(rect.fRight + rad, rect.fTop - rad);
902 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
903 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
904 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
905 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
906 verts[8] = verts[0];
907 verts[9] = verts[1];
908}
909
bsalomon@google.com205d4602011-04-25 12:43:45 +0000910static void setInsetFan(GrPoint* pts, size_t stride,
911 const GrRect& r, GrScalar dx, GrScalar dy) {
912 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
913}
914
915static const uint16_t gFillAARectIdx[] = {
916 0, 1, 5, 5, 4, 0,
917 1, 2, 6, 6, 5, 1,
918 2, 3, 7, 7, 6, 2,
919 3, 0, 4, 4, 7, 3,
920 4, 5, 6, 6, 7, 4,
921};
922
923int GrContext::aaFillRectIndexCount() const {
924 return GR_ARRAY_COUNT(gFillAARectIdx);
925}
926
927GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
928 if (NULL == fAAFillRectIndexBuffer) {
929 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
930 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000931 if (NULL != fAAFillRectIndexBuffer) {
932 #if GR_DEBUG
933 bool updated =
934 #endif
935 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
936 sizeof(gFillAARectIdx));
937 GR_DEBUGASSERT(updated);
938 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000939 }
940 return fAAFillRectIndexBuffer;
941}
942
943static const uint16_t gStrokeAARectIdx[] = {
944 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
945 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
946 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
947 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
948
949 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
950 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
951 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
952 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
953
954 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
955 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
956 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
957 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
958};
959
960int GrContext::aaStrokeRectIndexCount() const {
961 return GR_ARRAY_COUNT(gStrokeAARectIdx);
962}
963
964GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
965 if (NULL == fAAStrokeRectIndexBuffer) {
966 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
967 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000968 if (NULL != fAAStrokeRectIndexBuffer) {
969 #if GR_DEBUG
970 bool updated =
971 #endif
972 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
973 sizeof(gStrokeAARectIdx));
974 GR_DEBUGASSERT(updated);
975 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000976 }
977 return fAAStrokeRectIndexBuffer;
978}
979
bsalomon@google.coma3108262011-10-10 14:08:47 +0000980static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
981 bool useCoverage) {
982 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000983 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000984 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000985 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
986 }
987 }
988 if (useCoverage) {
989 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
990 } else {
991 layout |= GrDrawTarget::kColor_VertexLayoutBit;
992 }
993 return layout;
994}
995
bsalomon@google.com205d4602011-04-25 12:43:45 +0000996void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000997 const GrRect& devRect,
998 bool useVertexCoverage) {
999 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001000
1001 size_t vsize = GrDrawTarget::VertexSize(layout);
1002
1003 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001004 if (!geo.succeeded()) {
1005 GrPrintf("Failed to get space for vertices!\n");
1006 return;
1007 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001008 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1009 if (NULL == indexBuffer) {
1010 GrPrintf("Failed to create index buffer!\n");
1011 return;
1012 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001013
1014 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1015
1016 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1017 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1018
1019 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1020 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1021
1022 verts += sizeof(GrPoint);
1023 for (int i = 0; i < 4; ++i) {
1024 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1025 }
1026
bsalomon@google.coma3108262011-10-10 14:08:47 +00001027 GrColor innerColor;
1028 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001029 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001030 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001031 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001032 }
1033
bsalomon@google.com205d4602011-04-25 12:43:45 +00001034 verts += 4 * vsize;
1035 for (int i = 0; i < 4; ++i) {
1036 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1037 }
1038
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001039 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001040
1041 target->drawIndexed(kTriangles_PrimitiveType, 0,
1042 0, 8, this->aaFillRectIndexCount());
1043}
1044
bsalomon@google.coma3108262011-10-10 14:08:47 +00001045void GrContext::strokeAARect(GrDrawTarget* target,
1046 const GrRect& devRect,
1047 const GrVec& devStrokeSize,
1048 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001049 const GrScalar& dx = devStrokeSize.fX;
1050 const GrScalar& dy = devStrokeSize.fY;
1051 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1052 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1053
bsalomon@google.com205d4602011-04-25 12:43:45 +00001054 GrScalar spare;
1055 {
1056 GrScalar w = devRect.width() - dx;
1057 GrScalar h = devRect.height() - dy;
1058 spare = GrMin(w, h);
1059 }
1060
1061 if (spare <= 0) {
1062 GrRect r(devRect);
1063 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001064 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001065 return;
1066 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001067 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001068 size_t vsize = GrDrawTarget::VertexSize(layout);
1069
1070 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001071 if (!geo.succeeded()) {
1072 GrPrintf("Failed to get space for vertices!\n");
1073 return;
1074 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001075 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1076 if (NULL == indexBuffer) {
1077 GrPrintf("Failed to create index buffer!\n");
1078 return;
1079 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001080
1081 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1082
1083 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1084 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1085 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1086 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1087
1088 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1089 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1090 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1091 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1092
1093 verts += sizeof(GrPoint);
1094 for (int i = 0; i < 4; ++i) {
1095 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1096 }
1097
bsalomon@google.coma3108262011-10-10 14:08:47 +00001098 GrColor innerColor;
1099 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001100 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001101 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001102 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001103 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001104 verts += 4 * vsize;
1105 for (int i = 0; i < 8; ++i) {
1106 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1107 }
1108
1109 verts += 8 * vsize;
1110 for (int i = 0; i < 8; ++i) {
1111 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1112 }
1113
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001114 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001115 target->drawIndexed(kTriangles_PrimitiveType,
1116 0, 0, 16, aaStrokeRectIndexCount());
1117}
1118
reed@google.com20efde72011-05-09 17:00:02 +00001119/**
1120 * Returns true if the rects edges are integer-aligned.
1121 */
1122static bool isIRect(const GrRect& r) {
1123 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1124 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1125}
1126
bsalomon@google.com205d4602011-04-25 12:43:45 +00001127static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001128 const GrRect& rect,
1129 GrScalar width,
1130 const GrMatrix* matrix,
1131 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001132 GrRect* devRect,
1133 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001134 // we use a simple coverage ramp to do aa on axis-aligned rects
1135 // we check if the rect will be axis-aligned, and the rect won't land on
1136 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001137
bsalomon@google.coma3108262011-10-10 14:08:47 +00001138 // we are keeping around the "tweak the alpha" trick because
1139 // it is our only hope for the fixed-pipe implementation.
1140 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001141 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001142 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001143 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001144 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001145#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001146 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001147#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001148 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001149 } else {
1150 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001151 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001152 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001153 const GrDrawState& drawState = target->getDrawState();
1154 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001155 return false;
1156 }
1157
bsalomon@google.com471d4712011-08-23 15:45:25 +00001158 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001159 return false;
1160 }
1161
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001162 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001163 return false;
1164 }
1165
1166 if (NULL != matrix &&
1167 !matrix->preservesAxisAlignment()) {
1168 return false;
1169 }
1170
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001171 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001172 if (NULL != matrix) {
1173 combinedMatrix->preConcat(*matrix);
1174 GrAssert(combinedMatrix->preservesAxisAlignment());
1175 }
1176
1177 combinedMatrix->mapRect(devRect, rect);
1178 devRect->sort();
1179
1180 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001181 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001182 } else {
1183 return true;
1184 }
1185}
1186
bsalomon@google.com27847de2011-02-22 20:59:41 +00001187void GrContext::drawRect(const GrPaint& paint,
1188 const GrRect& rect,
1189 GrScalar width,
1190 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001191 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001192
1193 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001194 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001195
bsalomon@google.com205d4602011-04-25 12:43:45 +00001196 GrRect devRect = rect;
1197 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001198 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001199 bool needAA = paint.fAntiAlias &&
1200 !this->getRenderTarget()->isMultisampled();
1201 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1202 &combinedMatrix, &devRect,
1203 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001204
1205 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001206 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001207 if (width >= 0) {
1208 GrVec strokeSize;;
1209 if (width > 0) {
1210 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001211 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001212 strokeSize.setAbs(strokeSize);
1213 } else {
1214 strokeSize.set(GR_Scalar1, GR_Scalar1);
1215 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001216 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001217 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001218 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001219 }
1220 return;
1221 }
1222
bsalomon@google.com27847de2011-02-22 20:59:41 +00001223 if (width >= 0) {
1224 // TODO: consider making static vertex buffers for these cases.
1225 // Hairline could be done by just adding closing vertex to
1226 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001227 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1228
bsalomon@google.com27847de2011-02-22 20:59:41 +00001229 static const int worstCaseVertCount = 10;
1230 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1231
1232 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001233 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234 return;
1235 }
1236
1237 GrPrimitiveType primType;
1238 int vertCount;
1239 GrPoint* vertex = geo.positions();
1240
1241 if (width > 0) {
1242 vertCount = 10;
1243 primType = kTriangleStrip_PrimitiveType;
1244 setStrokeRectStrip(vertex, rect, width);
1245 } else {
1246 // hairline
1247 vertCount = 5;
1248 primType = kLineStrip_PrimitiveType;
1249 vertex[0].set(rect.fLeft, rect.fTop);
1250 vertex[1].set(rect.fRight, rect.fTop);
1251 vertex[2].set(rect.fRight, rect.fBottom);
1252 vertex[3].set(rect.fLeft, rect.fBottom);
1253 vertex[4].set(rect.fLeft, rect.fTop);
1254 }
1255
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001256 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001257 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001258 GrDrawState* drawState = target->drawState();
1259 avmr.set(drawState);
1260 drawState->preConcatViewMatrix(*matrix);
1261 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001262 }
1263
1264 target->drawNonIndexed(primType, 0, vertCount);
1265 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001266#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001267 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001268 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1269 if (NULL == sqVB) {
1270 GrPrintf("Failed to create static rect vb.\n");
1271 return;
1272 }
1273 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001274 GrDrawState* drawState = target->drawState();
1275 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001276 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001277 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001278 0, rect.height(), rect.fTop,
1279 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001280
1281 if (NULL != matrix) {
1282 m.postConcat(*matrix);
1283 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001284 drawState->preConcatViewMatrix(m);
1285 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001286
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001288#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001289 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001290#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001291 }
1292}
1293
1294void GrContext::drawRectToRect(const GrPaint& paint,
1295 const GrRect& dstRect,
1296 const GrRect& srcRect,
1297 const GrMatrix* dstMatrix,
1298 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001299 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001301 // srcRect refers to paint's first texture
1302 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001303 drawRect(paint, dstRect, -1, dstMatrix);
1304 return;
1305 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001306
bsalomon@google.com27847de2011-02-22 20:59:41 +00001307 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1308
1309#if GR_STATIC_RECT_VB
1310 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001311 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001312 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001313 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314
1315 GrMatrix m;
1316
1317 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1318 0, dstRect.height(), dstRect.fTop,
1319 0, 0, GrMatrix::I()[8]);
1320 if (NULL != dstMatrix) {
1321 m.postConcat(*dstMatrix);
1322 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001323 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001325 // srcRect refers to first stage
1326 int otherStageMask = paint.getActiveStageMask() &
1327 (~(1 << GrPaint::kFirstTextureStage));
1328 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001329 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001330 }
1331
bsalomon@google.com27847de2011-02-22 20:59:41 +00001332 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1333 0, srcRect.height(), srcRect.fTop,
1334 0, 0, GrMatrix::I()[8]);
1335 if (NULL != srcMatrix) {
1336 m.postConcat(*srcMatrix);
1337 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001338 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001339
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001340 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1341 if (NULL == sqVB) {
1342 GrPrintf("Failed to create static rect vb.\n");
1343 return;
1344 }
1345 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001346 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1347#else
1348
1349 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001350#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001351 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001352#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001353 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1354#endif
1355
tomhudson@google.com93813632011-10-27 20:21:16 +00001356 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1357 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001358 srcRects[0] = &srcRect;
1359 srcMatrices[0] = srcMatrix;
1360
1361 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1362#endif
1363}
1364
1365void GrContext::drawVertices(const GrPaint& paint,
1366 GrPrimitiveType primitiveType,
1367 int vertexCount,
1368 const GrPoint positions[],
1369 const GrPoint texCoords[],
1370 const GrColor colors[],
1371 const uint16_t indices[],
1372 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001373 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001374
1375 GrDrawTarget::AutoReleaseGeometry geo;
1376
1377 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1378
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001379 bool hasTexCoords[GrPaint::kTotalStages] = {
1380 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1381 0 // remaining stages use positions
1382 };
1383
1384 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001385
1386 if (NULL != colors) {
1387 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001388 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001389 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001390
1391 if (sizeof(GrPoint) != vertexSize) {
1392 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001393 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001394 return;
1395 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001396 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001398 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1399 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001400 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001401 NULL,
1402 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001403 void* curVertex = geo.vertices();
1404
1405 for (int i = 0; i < vertexCount; ++i) {
1406 *((GrPoint*)curVertex) = positions[i];
1407
1408 if (texOffsets[0] > 0) {
1409 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1410 }
1411 if (colorOffset > 0) {
1412 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1413 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001414 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 }
1416 } else {
1417 target->setVertexSourceToArray(layout, positions, vertexCount);
1418 }
1419
bsalomon@google.com91958362011-06-13 17:58:13 +00001420 // we don't currently apply offscreen AA to this path. Need improved
1421 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001422
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001423 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001424 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001425 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001426 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001427 target->drawNonIndexed(primitiveType, 0, vertexCount);
1428 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001429}
1430
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001431///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001432#include "SkDraw.h"
1433#include "SkRasterClip.h"
1434
1435namespace {
1436
1437SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1438 switch (fill) {
1439 case kWinding_PathFill:
1440 return SkPath::kWinding_FillType;
1441 case kEvenOdd_PathFill:
1442 return SkPath::kEvenOdd_FillType;
1443 case kInverseWinding_PathFill:
1444 return SkPath::kInverseWinding_FillType;
1445 case kInverseEvenOdd_PathFill:
1446 return SkPath::kInverseEvenOdd_FillType;
1447 default:
1448 GrCrash("Unexpected fill.");
1449 return SkPath::kWinding_FillType;
1450 }
1451}
1452
1453// gets device coord bounds of path (not considering the fill) and clip. The
1454// path bounds will be a subset of the clip bounds. returns false if path bounds
1455// would be empty.
1456bool get_path_and_clip_bounds(const GrDrawTarget* target,
1457 const GrPath& path,
1458 const GrVec* translate,
1459 GrIRect* pathBounds,
1460 GrIRect* clipBounds) {
1461 // compute bounds as intersection of rt size, clip, and path
1462 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1463 if (NULL == rt) {
1464 return false;
1465 }
1466 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1467 const GrClip& clip = target->getClip();
1468 if (clip.hasConservativeBounds()) {
1469 clip.getConservativeBounds().roundOut(clipBounds);
1470 if (!pathBounds->intersect(*clipBounds)) {
1471 return false;
1472 }
1473 } else {
1474 // pathBounds is currently the rt extent, set clip bounds to that rect.
1475 *clipBounds = *pathBounds;
1476 }
1477 GrRect pathSBounds = path.getBounds();
1478 if (!pathSBounds.isEmpty()) {
1479 if (NULL != translate) {
1480 pathSBounds.offset(*translate);
1481 }
1482 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1483 pathSBounds);
1484 GrIRect pathIBounds;
1485 pathSBounds.roundOut(&pathIBounds);
1486 if (!pathBounds->intersect(pathIBounds)) {
1487 return false;
1488 }
1489 } else {
1490 return false;
1491 }
1492 return true;
1493}
1494
1495/**
1496 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1497 * scratch texture.
1498 */
1499
1500bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1501 const GrIRect& pathDevBounds,
1502 GrPathFill fill,
1503 GrContext* context,
1504 const GrPoint* translate,
1505 GrAutoScratchTexture* tex) {
1506 SkPaint paint;
1507 SkPath tmpPath;
1508 const SkPath* pathToDraw = &clientPath;
1509 if (kHairLine_PathFill == fill) {
1510 paint.setStyle(SkPaint::kStroke_Style);
1511 paint.setStrokeWidth(SK_Scalar1);
1512 } else {
1513 paint.setStyle(SkPaint::kFill_Style);
1514 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1515 if (skfill != pathToDraw->getFillType()) {
1516 tmpPath = *pathToDraw;
1517 tmpPath.setFillType(skfill);
1518 pathToDraw = &tmpPath;
1519 }
1520 }
1521 paint.setAntiAlias(true);
1522 paint.setColor(SK_ColorWHITE);
1523
1524 GrMatrix matrix = context->getMatrix();
1525 if (NULL != translate) {
1526 matrix.postTranslate(translate->fX, translate->fY);
1527 }
1528
1529 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1530 -pathDevBounds.fTop * SK_Scalar1);
1531 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1532 pathDevBounds.height());
1533
1534 SkBitmap bm;
1535 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1536 if (!bm.allocPixels()) {
1537 return false;
1538 }
1539 sk_bzero(bm.getPixels(), bm.getSafeSize());
1540
1541 SkDraw draw;
1542 sk_bzero(&draw, sizeof(draw));
1543 SkRasterClip rc(bounds);
1544 draw.fRC = &rc;
1545 draw.fClip = &rc.bwRgn();
1546 draw.fMatrix = &matrix;
1547 draw.fBitmap = &bm;
1548 draw.drawPath(*pathToDraw, paint);
1549
1550 const GrTextureDesc desc = {
1551 kNone_GrTextureFlags,
bsalomon@google.com150d2842012-01-12 20:19:56 +00001552 bounds.fRight,
1553 bounds.fBottom,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001554 kAlpha_8_GrPixelConfig,
1555 {0} // samples
bsalomon@google.com150d2842012-01-12 20:19:56 +00001556 };
1557
1558 tex->set(context, desc);
1559 GrTexture* texture = tex->texture();
1560
1561 if (NULL == texture) {
1562 return false;
1563 }
1564 SkAutoLockPixels alp(bm);
1565 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1566 bm.getPixels(), bm.rowBytes());
1567 return true;
1568}
1569
1570void draw_around_inv_path(GrDrawTarget* target,
1571 GrDrawState::StageMask stageMask,
1572 const GrIRect& clipBounds,
1573 const GrIRect& pathBounds) {
1574 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1575 GrRect rect;
1576 if (clipBounds.fTop < pathBounds.fTop) {
1577 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1578 clipBounds.fRight, pathBounds.fTop);
1579 target->drawSimpleRect(rect, NULL, stageMask);
1580 }
1581 if (clipBounds.fLeft < pathBounds.fLeft) {
1582 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1583 pathBounds.fLeft, pathBounds.fBottom);
1584 target->drawSimpleRect(rect, NULL, stageMask);
1585 }
1586 if (clipBounds.fRight > pathBounds.fRight) {
1587 rect.iset(pathBounds.fRight, pathBounds.fTop,
1588 clipBounds.fRight, pathBounds.fBottom);
1589 target->drawSimpleRect(rect, NULL, stageMask);
1590 }
1591 if (clipBounds.fBottom > pathBounds.fBottom) {
1592 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1593 clipBounds.fRight, clipBounds.fBottom);
1594 target->drawSimpleRect(rect, NULL, stageMask);
1595 }
1596}
1597
1598}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001599
reed@google.com07f3ee12011-05-16 17:21:57 +00001600void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1601 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001602
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001603 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001604 if (GrIsFillInverted(fill)) {
1605 this->drawPaint(paint);
1606 }
1607 return;
1608 }
1609
bsalomon@google.com27847de2011-02-22 20:59:41 +00001610 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001611 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001612
bsalomon@google.com289533a2011-10-27 12:34:25 +00001613 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1614
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001615 // An Assumption here is that path renderer would use some form of tweaking
1616 // the src color (either the input alpha or in the frag shader) to implement
1617 // aa. If we have some future driver-mojo path AA that can do the right
1618 // thing WRT to the blend then we'll need some query on the PR.
1619 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001620#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001621 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001622#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001623 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001624 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001625
1626 bool doOSAA = false;
1627 GrPathRenderer* pr = NULL;
1628 if (prAA) {
1629 pr = this->getPathRenderer(path, fill, true);
1630 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001631 GrAutoScratchTexture ast;
1632 GrIRect pathBounds, clipBounds;
1633 if (!get_path_and_clip_bounds(target, path, translate,
1634 &pathBounds, &clipBounds)) {
1635 return;
1636 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001637 prAA = false;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001638 if (this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
1639 pr = this->getPathRenderer(path, fill, false);
1640 doOSAA = true;
1641 }
1642 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1643 fill, this,
1644 translate, &ast)) {
1645 GrTexture* texture = ast.texture();
1646 GrAssert(NULL != texture);
1647 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1648 enum {
1649 kPathMaskStage = GrPaint::kTotalStages,
1650 };
1651 target->drawState()->setTexture(kPathMaskStage, texture);
1652 target->drawState()->sampler(kPathMaskStage)->reset();
1653 GrScalar w = GrIntToScalar(pathBounds.width());
1654 GrScalar h = GrIntToScalar(pathBounds.height());
1655 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1656 h / texture->height());
1657 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1658 srcRects[kPathMaskStage] = &maskRect;
1659 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001660 GrRect dstRect = GrRect::MakeLTRB(
1661 SK_Scalar1* pathBounds.fLeft,
1662 SK_Scalar1* pathBounds.fTop,
1663 SK_Scalar1* pathBounds.fRight,
1664 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001665 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1666 target->drawState()->setTexture(kPathMaskStage, NULL);
1667 if (GrIsFillInverted(fill)) {
1668 draw_around_inv_path(target, stageMask,
1669 clipBounds, pathBounds);
1670 }
1671 return;
1672 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001673 }
1674 } else {
1675 pr = this->getPathRenderer(path, fill, false);
1676 }
1677
bsalomon@google.com30085192011-08-19 15:42:31 +00001678 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001679#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001680 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001681#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001682 return;
1683 }
1684
bsalomon@google.com289533a2011-10-27 12:34:25 +00001685 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001686
bsalomon@google.com289533a2011-10-27 12:34:25 +00001687 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001688 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001689 GrIRect pathBounds;
1690 GrIRect clipBounds;
1691 if (!get_path_and_clip_bounds(target, path, translate,
1692 &pathBounds, &clipBounds)) {
1693 return;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001694 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001695 OffscreenRecord record;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001696 if (this->prepareForOffscreenAA(target, needsStencil, pathBounds,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001697 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001698 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1699 for (int ty = 0; ty < record.fTileCountY; ++ty) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001700 this->setupOffscreenAAPass1(target, pathBounds,
1701 tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001702 pr->drawPath(0);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001703 this->doOffscreenAAPass2(target, paint, pathBounds,
1704 tx, ty, &record);
bsalomon@google.com91958362011-06-13 17:58:13 +00001705 }
1706 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001707 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001708 if (GrIsFillInverted(fill)) {
1709 draw_around_inv_path(target, stageMask, clipBounds, pathBounds);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001710 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001711 return;
1712 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001713 }
1714 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001715}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001716
bsalomon@google.com27847de2011-02-22 20:59:41 +00001717////////////////////////////////////////////////////////////////////////////////
1718
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001719void GrContext::flush(int flagsBitfield) {
1720 if (kDiscard_FlushBit & flagsBitfield) {
1721 fDrawBuffer->reset();
1722 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001723 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001724 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001725 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001726 fGpu->forceRenderTargetFlush();
1727 }
1728}
1729
1730void GrContext::flushText() {
1731 if (kText_DrawCategory == fLastDrawCategory) {
1732 flushDrawBuffer();
1733 }
1734}
1735
1736void GrContext::flushDrawBuffer() {
1737#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001738 if (fDrawBuffer) {
1739 fDrawBuffer->playback(fGpu);
1740 fDrawBuffer->reset();
1741 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001742#endif
1743}
1744
bsalomon@google.com6f379512011-11-16 20:36:03 +00001745void GrContext::internalWriteTexturePixels(GrTexture* texture,
1746 int left, int top,
1747 int width, int height,
1748 GrPixelConfig config,
1749 const void* buffer,
1750 size_t rowBytes,
1751 uint32_t flags) {
1752 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001753 ASSERT_OWNED_RESOURCE(texture);
1754
bsalomon@google.com6f379512011-11-16 20:36:03 +00001755 if (!(kDontFlush_PixelOpsFlag & flags)) {
1756 this->flush();
1757 }
1758 // TODO: use scratch texture to perform conversion
1759 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1760 GrPixelConfigIsUnpremultiplied(config)) {
1761 return;
1762 }
1763
1764 fGpu->writeTexturePixels(texture, left, top, width, height,
1765 config, buffer, rowBytes);
1766}
1767
1768bool GrContext::internalReadTexturePixels(GrTexture* texture,
1769 int left, int top,
1770 int width, int height,
1771 GrPixelConfig config,
1772 void* buffer,
1773 size_t rowBytes,
1774 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001775 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001776 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001777
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001778 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001779 GrRenderTarget* target = texture->asRenderTarget();
1780 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001781 return this->internalReadRenderTargetPixels(target,
1782 left, top, width, height,
1783 config, buffer, rowBytes,
1784 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001785 } else {
1786 return false;
1787 }
1788}
1789
bsalomon@google.com6f379512011-11-16 20:36:03 +00001790bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1791 int left, int top,
1792 int width, int height,
1793 GrPixelConfig config,
1794 void* buffer,
1795 size_t rowBytes,
1796 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001797 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001798 ASSERT_OWNED_RESOURCE(target);
1799
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001800 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001801 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001802 if (NULL == target) {
1803 return false;
1804 }
1805 }
1806
1807 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1808 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1809 // not supported at this time.
1810 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1811 !GrPixelConfigIsUnpremultiplied(config)) {
1812 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001813 }
1814
bsalomon@google.com6f379512011-11-16 20:36:03 +00001815 if (!(kDontFlush_PixelOpsFlag & flags)) {
1816 this->flush();
1817 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001818
1819 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001820 bool swapRAndB = NULL != src &&
1821 fGpu->preferredReadPixelsConfig(config) ==
1822 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001823
1824 bool flipY = NULL != src &&
1825 fGpu->readPixelsWillPayForYFlip(target, left, top,
1826 width, height, config,
1827 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001828 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1829 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001830
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001831 if (NULL == src && alphaConversion) {
1832 // we should fallback to cpu conversion here. This could happen when
1833 // we were given an external render target by the client that is not
1834 // also a texture (e.g. FBO 0 in GL)
1835 return false;
1836 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001837 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001838 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001839 if (flipY || swapRAndB || alphaConversion) {
1840 GrAssert(NULL != src);
1841 if (swapRAndB) {
1842 config = GrPixelConfigSwapRAndB(config);
1843 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001844 }
1845 // Make the scratch a render target because we don't have a robust
1846 // readTexturePixels as of yet (it calls this function).
1847 const GrTextureDesc desc = {
1848 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001849 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001850 config,
1851 {0}, // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001852 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001853
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001854 // When a full readback is faster than a partial we could always make
1855 // the scratch exactly match the passed rect. However, if we see many
1856 // different size rectangles we will trash our texture cache and pay the
1857 // cost of creating and destroying many textures. So, we only request
1858 // an exact match when the caller is reading an entire RT.
1859 ScratchTexMatch match = kApprox_ScratchTexMatch;
1860 if (0 == left &&
1861 0 == top &&
1862 target->width() == width &&
1863 target->height() == height &&
1864 fGpu->fullReadPixelsIsFasterThanPartial()) {
1865 match = kExact_ScratchTexMatch;
1866 }
1867 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001868 GrTexture* texture = ast.texture();
1869 if (!texture) {
1870 return false;
1871 }
1872 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001873 GrAssert(NULL != target);
1874
1875 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001876 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001877 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001878 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001879
bsalomon@google.comc4364992011-11-07 15:54:49 +00001880 GrMatrix matrix;
1881 if (flipY) {
1882 matrix.setTranslate(SK_Scalar1 * left,
1883 SK_Scalar1 * (top + height));
1884 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1885 } else {
1886 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1887 }
1888 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001889 drawState->sampler(0)->reset(matrix);
1890 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001891 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001892 GrRect rect;
1893 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1894 fGpu->drawSimpleRect(rect, NULL, 0x1);
1895 left = 0;
1896 top = 0;
1897 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001898 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001899 left, top, width, height,
1900 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001901}
1902
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001903void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1904 GrAssert(target);
1905 ASSERT_OWNED_RESOURCE(target);
1906 // In the future we may track whether there are any pending draws to this
1907 // target. We don't today so we always perform a flush. We don't promise
1908 // this to our clients, though.
1909 this->flush();
1910 fGpu->resolveRenderTarget(target);
1911}
1912
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001913void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1914 if (NULL == src || NULL == dst) {
1915 return;
1916 }
1917 ASSERT_OWNED_RESOURCE(src);
1918
1919 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001920 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001921 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001922 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001923 GrMatrix sampleM;
1924 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001925 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001926 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001927 SkRect rect = SkRect::MakeXYWH(0, 0,
1928 SK_Scalar1 * src->width(),
1929 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001930 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1931}
1932
bsalomon@google.com6f379512011-11-16 20:36:03 +00001933void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1934 int left, int top,
1935 int width, int height,
1936 GrPixelConfig config,
1937 const void* buffer,
1938 size_t rowBytes,
1939 uint32_t flags) {
1940 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001941 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001942
1943 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001944 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001945 if (NULL == target) {
1946 return;
1947 }
1948 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001949
1950 // TODO: when underlying api has a direct way to do this we should use it
1951 // (e.g. glDrawPixels on desktop GL).
1952
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001953 // If the RT is also a texture and we don't have to do PM/UPM conversion
1954 // then take the texture path, which we expect to be at least as fast or
1955 // faster since it doesn't use an intermediate texture as we do below.
1956
1957#if !GR_MAC_BUILD
1958 // At least some drivers on the Mac get confused when glTexImage2D is called
1959 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1960 // determine what OS versions and/or HW is affected.
1961 if (NULL != target->asTexture() &&
1962 GrPixelConfigIsUnpremultiplied(target->config()) ==
1963 GrPixelConfigIsUnpremultiplied(config)) {
1964
1965 this->internalWriteTexturePixels(target->asTexture(),
1966 left, top, width, height,
1967 config, buffer, rowBytes, flags);
1968 return;
1969 }
1970#endif
1971
1972 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1973 GrPixelConfigSwapRAndB(config);
1974 if (swapRAndB) {
1975 config = GrPixelConfigSwapRAndB(config);
1976 }
1977
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001978 const GrTextureDesc desc = {
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001979 kNone_GrTextureFlags, width, height, config, {0}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001980 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001981 GrAutoScratchTexture ast(this, desc);
1982 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001983 if (NULL == texture) {
1984 return;
1985 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001986 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1987 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001988
bsalomon@google.com27847de2011-02-22 20:59:41 +00001989 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001990 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001991 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001992
1993 GrMatrix matrix;
1994 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001995 drawState->setViewMatrix(matrix);
1996 drawState->setRenderTarget(target);
1997 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001998
bsalomon@google.com5c638652011-07-18 19:31:59 +00001999 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002000 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2001 GrSamplerState::kNearest_Filter,
2002 matrix);
2003 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002004
2005 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
2006 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002007 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00002008 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
2009 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002010 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00002011 return;
2012 }
2013 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
2014 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
2015}
2016////////////////////////////////////////////////////////////////////////////////
2017
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002018void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002019 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002020
2021 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
2022 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002023 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002024 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002025 if (paint.getTexture(i)) {
2026 *drawState->sampler(s) = paint.getTextureSampler(i);
2027 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002028 }
2029
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002030 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002031
2032 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
2033 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002034 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002035 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002036 if (paint.getMask(i)) {
2037 *drawState->sampler(s) = paint.getMaskSampler(i);
2038 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002039 }
2040
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002041 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002042
2043 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002044 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002045 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002046 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002047 }
2048 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002049 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002050 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002051 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002052 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002053 if (paint.fColorMatrixEnabled) {
2054 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
2055 } else {
2056 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
2057 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002058 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002059 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002060 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comdd1be602012-01-18 20:34:00 +00002061 drawState->setCoverage(paint.fCoverage);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00002062
2063 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
2064 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
2065 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002066}
2067
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002068GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002069 DrawCategory category) {
2070 if (category != fLastDrawCategory) {
2071 flushDrawBuffer();
2072 fLastDrawCategory = category;
2073 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002074 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002075 GrDrawTarget* target = fGpu;
2076 switch (category) {
2077 case kText_DrawCategory:
2078#if DEFER_TEXT_RENDERING
2079 target = fDrawBuffer;
2080 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2081#else
2082 target = fGpu;
2083#endif
2084 break;
2085 case kUnbuffered_DrawCategory:
2086 target = fGpu;
2087 break;
2088 case kBuffered_DrawCategory:
2089 target = fDrawBuffer;
2090 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2091 break;
2092 }
2093 return target;
2094}
2095
bsalomon@google.com289533a2011-10-27 12:34:25 +00002096GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
2097 GrPathFill fill,
2098 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00002099 if (NULL == fPathRendererChain) {
2100 fPathRendererChain =
2101 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
2102 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00002103 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
2104 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00002105}
2106
bsalomon@google.com27847de2011-02-22 20:59:41 +00002107////////////////////////////////////////////////////////////////////////////////
2108
bsalomon@google.com27847de2011-02-22 20:59:41 +00002109void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002110 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002111 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002112 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002113}
2114
2115GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002116 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002117}
2118
2119const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002120 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002121}
2122
2123const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002124 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002125}
2126
2127void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002128 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002129}
2130
2131void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002132 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002133}
2134
2135static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2136 intptr_t mask = 1 << shift;
2137 if (pred) {
2138 bits |= mask;
2139 } else {
2140 bits &= ~mask;
2141 }
2142 return bits;
2143}
2144
2145void GrContext::resetStats() {
2146 fGpu->resetStats();
2147}
2148
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002149const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002150 return fGpu->getStats();
2151}
2152
2153void GrContext::printStats() const {
2154 fGpu->printStats();
2155}
2156
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002157GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002158 fGpu = gpu;
2159 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002160 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002161
bsalomon@google.com30085192011-08-19 15:42:31 +00002162 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002163
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002164 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2165 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002166 fFontCache = new GrFontCache(fGpu);
2167
2168 fLastDrawCategory = kUnbuffered_DrawCategory;
2169
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002170 fDrawBuffer = NULL;
2171 fDrawBufferVBAllocPool = NULL;
2172 fDrawBufferIBAllocPool = NULL;
2173
bsalomon@google.com205d4602011-04-25 12:43:45 +00002174 fAAFillRectIndexBuffer = NULL;
2175 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002176
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002177 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2178 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002179 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2180 }
2181 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002182
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002183 this->setupDrawBuffer();
2184}
2185
2186void GrContext::setupDrawBuffer() {
2187
2188 GrAssert(NULL == fDrawBuffer);
2189 GrAssert(NULL == fDrawBufferVBAllocPool);
2190 GrAssert(NULL == fDrawBufferIBAllocPool);
2191
bsalomon@google.com27847de2011-02-22 20:59:41 +00002192#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002193 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002194 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002195 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2196 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002197 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002198 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002199 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002200 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2201
bsalomon@google.com471d4712011-08-23 15:45:25 +00002202 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2203 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002204 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002205#endif
2206
2207#if BATCH_RECT_TO_RECT
2208 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2209#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002210}
2211
bsalomon@google.com27847de2011-02-22 20:59:41 +00002212GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2213 GrDrawTarget* target;
2214#if DEFER_TEXT_RENDERING
2215 target = prepareToDraw(paint, kText_DrawCategory);
2216#else
2217 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2218#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002219 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002220 return target;
2221}
2222
2223const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2224 return fGpu->getQuadIndexBuffer();
2225}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002226
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002227void GrContext::convolveInX(GrTexture* texture,
2228 const SkRect& rect,
2229 const float* kernel,
2230 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002231 ASSERT_OWNED_RESOURCE(texture);
2232
bsalomon@google.com99621082011-11-15 16:47:16 +00002233 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002234 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2235}
2236
2237void GrContext::convolveInY(GrTexture* texture,
2238 const SkRect& rect,
2239 const float* kernel,
2240 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002241 ASSERT_OWNED_RESOURCE(texture);
2242
bsalomon@google.com99621082011-11-15 16:47:16 +00002243 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002244 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2245}
2246
2247void GrContext::convolve(GrTexture* texture,
2248 const SkRect& rect,
2249 float imageIncrement[2],
2250 const float* kernel,
2251 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002252 ASSERT_OWNED_RESOURCE(texture);
2253
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002254 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002255 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.comdd1be602012-01-18 20:34:00 +00002256 GrRenderTarget* target = drawState->getRenderTarget();
2257 drawState->reset();
2258 drawState->setRenderTarget(target);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002259 GrMatrix sampleM;
2260 sampleM.setIDiv(texture->width(), texture->height());
2261 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2262 GrSamplerState::kConvolution_Filter,
2263 sampleM);
2264 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2265 kernel,
2266 imageIncrement);
2267
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002268 drawState->setTexture(0, texture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002269 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2270}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002271
2272///////////////////////////////////////////////////////////////////////////////