blob: 5f2c43b80b66456f65c8a36c2c288267bc868671 [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.coma91e9232012-02-23 15:39:54 +00001790#include "SkConfig8888.h"
1791
1792namespace {
1793/**
1794 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1795 * formats are representable as Config8888 and so the function returns false
1796 * if the GrPixelConfig has no equivalent Config8888.
1797 */
1798bool grconfig_to_config8888(GrPixelConfig config,
1799 SkCanvas::Config8888* config8888) {
1800 switch (config) {
1801 case kRGBA_8888_PM_GrPixelConfig:
1802 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1803 return true;
1804 case kRGBA_8888_UPM_GrPixelConfig:
1805 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1806 return true;
1807 case kBGRA_8888_PM_GrPixelConfig:
1808 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1809 return true;
1810 case kBGRA_8888_UPM_GrPixelConfig:
1811 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1812 return true;
1813 default:
1814 return false;
1815 }
1816}
1817}
1818
bsalomon@google.com6f379512011-11-16 20:36:03 +00001819bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1820 int left, int top,
1821 int width, int height,
1822 GrPixelConfig config,
1823 void* buffer,
1824 size_t rowBytes,
1825 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001826 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001827 ASSERT_OWNED_RESOURCE(target);
1828
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001829 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001830 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001831 if (NULL == target) {
1832 return false;
1833 }
1834 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001835
bsalomon@google.com6f379512011-11-16 20:36:03 +00001836 if (!(kDontFlush_PixelOpsFlag & flags)) {
1837 this->flush();
1838 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001839
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001840 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1841 GrPixelConfigIsUnpremultiplied(config) &&
1842 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1843 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1844 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1845 !grconfig_to_config8888(config, &dstConfig8888)) {
1846 return false;
1847 }
1848 // do read back using target's own config
1849 this->internalReadRenderTargetPixels(target,
1850 left, top,
1851 width, height,
1852 target->config(),
1853 buffer, rowBytes,
1854 kDontFlush_PixelOpsFlag);
1855 // sw convert the pixels to unpremul config
1856 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1857 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1858 pixels, rowBytes, srcConfig8888,
1859 width, height);
1860 return true;
1861 }
1862
bsalomon@google.comc4364992011-11-07 15:54:49 +00001863 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001864 bool swapRAndB = NULL != src &&
1865 fGpu->preferredReadPixelsConfig(config) ==
1866 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001867
1868 bool flipY = NULL != src &&
1869 fGpu->readPixelsWillPayForYFlip(target, left, top,
1870 width, height, config,
1871 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001872 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1873 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001874
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001875 if (NULL == src && alphaConversion) {
1876 // we should fallback to cpu conversion here. This could happen when
1877 // we were given an external render target by the client that is not
1878 // also a texture (e.g. FBO 0 in GL)
1879 return false;
1880 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001881 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001882 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001883 if (flipY || swapRAndB || alphaConversion) {
1884 GrAssert(NULL != src);
1885 if (swapRAndB) {
1886 config = GrPixelConfigSwapRAndB(config);
1887 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001888 }
1889 // Make the scratch a render target because we don't have a robust
1890 // readTexturePixels as of yet (it calls this function).
1891 const GrTextureDesc desc = {
1892 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001893 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001894 config,
1895 {0}, // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001896 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001897
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001898 // When a full readback is faster than a partial we could always make
1899 // the scratch exactly match the passed rect. However, if we see many
1900 // different size rectangles we will trash our texture cache and pay the
1901 // cost of creating and destroying many textures. So, we only request
1902 // an exact match when the caller is reading an entire RT.
1903 ScratchTexMatch match = kApprox_ScratchTexMatch;
1904 if (0 == left &&
1905 0 == top &&
1906 target->width() == width &&
1907 target->height() == height &&
1908 fGpu->fullReadPixelsIsFasterThanPartial()) {
1909 match = kExact_ScratchTexMatch;
1910 }
1911 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001912 GrTexture* texture = ast.texture();
1913 if (!texture) {
1914 return false;
1915 }
1916 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001917 GrAssert(NULL != target);
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(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001923
bsalomon@google.comc4364992011-11-07 15:54:49 +00001924 GrMatrix matrix;
1925 if (flipY) {
1926 matrix.setTranslate(SK_Scalar1 * left,
1927 SK_Scalar1 * (top + height));
1928 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1929 } else {
1930 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1931 }
1932 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001933 drawState->sampler(0)->reset(matrix);
1934 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001935 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001936 GrRect rect;
1937 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1938 fGpu->drawSimpleRect(rect, NULL, 0x1);
1939 left = 0;
1940 top = 0;
1941 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001942 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001943 left, top, width, height,
1944 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001945}
1946
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001947void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1948 GrAssert(target);
1949 ASSERT_OWNED_RESOURCE(target);
1950 // In the future we may track whether there are any pending draws to this
1951 // target. We don't today so we always perform a flush. We don't promise
1952 // this to our clients, though.
1953 this->flush();
1954 fGpu->resolveRenderTarget(target);
1955}
1956
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001957void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1958 if (NULL == src || NULL == dst) {
1959 return;
1960 }
1961 ASSERT_OWNED_RESOURCE(src);
1962
1963 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001964 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001965 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001966 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001967 GrMatrix sampleM;
1968 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001969 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001970 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001971 SkRect rect = SkRect::MakeXYWH(0, 0,
1972 SK_Scalar1 * src->width(),
1973 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001974 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1975}
1976
bsalomon@google.com6f379512011-11-16 20:36:03 +00001977void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1978 int left, int top,
1979 int width, int height,
1980 GrPixelConfig config,
1981 const void* buffer,
1982 size_t rowBytes,
1983 uint32_t flags) {
1984 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001985 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001986
1987 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001988 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001989 if (NULL == target) {
1990 return;
1991 }
1992 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993
1994 // TODO: when underlying api has a direct way to do this we should use it
1995 // (e.g. glDrawPixels on desktop GL).
1996
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001997 // If the RT is also a texture and we don't have to do PM/UPM conversion
1998 // then take the texture path, which we expect to be at least as fast or
1999 // faster since it doesn't use an intermediate texture as we do below.
2000
2001#if !GR_MAC_BUILD
2002 // At least some drivers on the Mac get confused when glTexImage2D is called
2003 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
2004 // determine what OS versions and/or HW is affected.
2005 if (NULL != target->asTexture() &&
2006 GrPixelConfigIsUnpremultiplied(target->config()) ==
2007 GrPixelConfigIsUnpremultiplied(config)) {
2008
2009 this->internalWriteTexturePixels(target->asTexture(),
2010 left, top, width, height,
2011 config, buffer, rowBytes, flags);
2012 return;
2013 }
2014#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00002015 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
2016 GrPixelConfigIsUnpremultiplied(config) &&
2017 !fGpu->canPreserveReadWriteUnpremulPixels()) {
2018 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
2019 if (!grconfig_to_config8888(config, &srcConfig8888) ||
2020 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
2021 return;
2022 }
2023 // allocate a tmp buffer and sw convert the pixels to premul
2024 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
2025 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
2026 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
2027 src, rowBytes, srcConfig8888,
2028 width, height);
2029 // upload the already premul pixels
2030 this->internalWriteRenderTargetPixels(target,
2031 left, top,
2032 width, height,
2033 target->config(),
2034 tmpPixels, 4 * width, flags);
2035 return;
2036 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00002037
2038 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
2039 GrPixelConfigSwapRAndB(config);
2040 if (swapRAndB) {
2041 config = GrPixelConfigSwapRAndB(config);
2042 }
2043
bsalomon@google.comfea37b52011-04-25 15:51:06 +00002044 const GrTextureDesc desc = {
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00002045 kNone_GrTextureFlags, width, height, config, {0}
bsalomon@google.com27847de2011-02-22 20:59:41 +00002046 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002047 GrAutoScratchTexture ast(this, desc);
2048 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002049 if (NULL == texture) {
2050 return;
2051 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00002052 this->internalWriteTexturePixels(texture, 0, 0, width, height,
2053 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002054
bsalomon@google.com27847de2011-02-22 20:59:41 +00002055 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002056 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00002057 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002058
2059 GrMatrix matrix;
2060 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002061 drawState->setViewMatrix(matrix);
2062 drawState->setRenderTarget(target);
2063 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002064
bsalomon@google.com5c638652011-07-18 19:31:59 +00002065 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002066 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2067 GrSamplerState::kNearest_Filter,
2068 matrix);
2069 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002070
2071 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
2072 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002073 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00002074 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
2075 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002076 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00002077 return;
2078 }
2079 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
2080 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
2081}
2082////////////////////////////////////////////////////////////////////////////////
2083
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002084void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002085 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002086
2087 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
2088 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002089 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002090 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002091 if (paint.getTexture(i)) {
2092 *drawState->sampler(s) = paint.getTextureSampler(i);
2093 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002094 }
2095
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002096 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002097
2098 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
2099 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002100 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002101 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002102 if (paint.getMask(i)) {
2103 *drawState->sampler(s) = paint.getMaskSampler(i);
2104 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002105 }
2106
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002107 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002108
2109 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002110 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002111 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002112 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002113 }
2114 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002115 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002116 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002117 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002118 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002119 if (paint.fColorMatrixEnabled) {
2120 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
2121 } else {
2122 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
2123 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002124 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002125 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002126 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comdd1be602012-01-18 20:34:00 +00002127 drawState->setCoverage(paint.fCoverage);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00002128
2129 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
2130 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
2131 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002132}
2133
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002134GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002135 DrawCategory category) {
2136 if (category != fLastDrawCategory) {
2137 flushDrawBuffer();
2138 fLastDrawCategory = category;
2139 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002140 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002141 GrDrawTarget* target = fGpu;
2142 switch (category) {
2143 case kText_DrawCategory:
2144#if DEFER_TEXT_RENDERING
2145 target = fDrawBuffer;
2146 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2147#else
2148 target = fGpu;
2149#endif
2150 break;
2151 case kUnbuffered_DrawCategory:
2152 target = fGpu;
2153 break;
2154 case kBuffered_DrawCategory:
2155 target = fDrawBuffer;
2156 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2157 break;
2158 }
2159 return target;
2160}
2161
bsalomon@google.com289533a2011-10-27 12:34:25 +00002162GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
2163 GrPathFill fill,
2164 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00002165 if (NULL == fPathRendererChain) {
2166 fPathRendererChain =
2167 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
2168 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00002169 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
2170 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00002171}
2172
bsalomon@google.com27847de2011-02-22 20:59:41 +00002173////////////////////////////////////////////////////////////////////////////////
2174
bsalomon@google.com27847de2011-02-22 20:59:41 +00002175void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002176 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002177 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002178 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002179}
2180
2181GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002182 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002183}
2184
2185const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002186 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002187}
2188
2189const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002190 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002191}
2192
2193void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002194 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002195}
2196
2197void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002198 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002199}
2200
2201static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2202 intptr_t mask = 1 << shift;
2203 if (pred) {
2204 bits |= mask;
2205 } else {
2206 bits &= ~mask;
2207 }
2208 return bits;
2209}
2210
2211void GrContext::resetStats() {
2212 fGpu->resetStats();
2213}
2214
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002215const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002216 return fGpu->getStats();
2217}
2218
2219void GrContext::printStats() const {
2220 fGpu->printStats();
2221}
2222
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002223GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002224 fGpu = gpu;
2225 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002226 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002227
bsalomon@google.com30085192011-08-19 15:42:31 +00002228 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002229
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002230 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2231 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002232 fFontCache = new GrFontCache(fGpu);
2233
2234 fLastDrawCategory = kUnbuffered_DrawCategory;
2235
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002236 fDrawBuffer = NULL;
2237 fDrawBufferVBAllocPool = NULL;
2238 fDrawBufferIBAllocPool = NULL;
2239
bsalomon@google.com205d4602011-04-25 12:43:45 +00002240 fAAFillRectIndexBuffer = NULL;
2241 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002242
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002243 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2244 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002245 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2246 }
2247 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002248
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002249 this->setupDrawBuffer();
2250}
2251
2252void GrContext::setupDrawBuffer() {
2253
2254 GrAssert(NULL == fDrawBuffer);
2255 GrAssert(NULL == fDrawBufferVBAllocPool);
2256 GrAssert(NULL == fDrawBufferIBAllocPool);
2257
bsalomon@google.com27847de2011-02-22 20:59:41 +00002258#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002259 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002260 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002261 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2262 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002263 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002264 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002265 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002266 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2267
bsalomon@google.com471d4712011-08-23 15:45:25 +00002268 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2269 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002270 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002271#endif
2272
2273#if BATCH_RECT_TO_RECT
2274 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2275#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002276}
2277
bsalomon@google.com27847de2011-02-22 20:59:41 +00002278GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2279 GrDrawTarget* target;
2280#if DEFER_TEXT_RENDERING
2281 target = prepareToDraw(paint, kText_DrawCategory);
2282#else
2283 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2284#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002285 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002286 return target;
2287}
2288
2289const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2290 return fGpu->getQuadIndexBuffer();
2291}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002292
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002293void GrContext::convolveInX(GrTexture* texture,
2294 const SkRect& rect,
2295 const float* kernel,
2296 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002297 ASSERT_OWNED_RESOURCE(texture);
2298
bsalomon@google.com99621082011-11-15 16:47:16 +00002299 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002300 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2301}
2302
2303void GrContext::convolveInY(GrTexture* texture,
2304 const SkRect& rect,
2305 const float* kernel,
2306 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002307 ASSERT_OWNED_RESOURCE(texture);
2308
bsalomon@google.com99621082011-11-15 16:47:16 +00002309 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002310 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2311}
2312
2313void GrContext::convolve(GrTexture* texture,
2314 const SkRect& rect,
2315 float imageIncrement[2],
2316 const float* kernel,
2317 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002318 ASSERT_OWNED_RESOURCE(texture);
2319
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002320 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002321 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.comdd1be602012-01-18 20:34:00 +00002322 GrRenderTarget* target = drawState->getRenderTarget();
2323 drawState->reset();
2324 drawState->setRenderTarget(target);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002325 GrMatrix sampleM;
2326 sampleM.setIDiv(texture->width(), texture->height());
2327 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2328 GrSamplerState::kConvolution_Filter,
2329 sampleM);
2330 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2331 kernel,
2332 imageIncrement);
2333
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002334 drawState->setTexture(0, texture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002335 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2336}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002337
2338///////////////////////////////////////////////////////////////////////////////