blob: 0a3ab422b6aa9b5bf3dce074eb327e2bb12ff97f [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
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000118////////////////////////////////////////////////////////////////////////////////
119
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000120int GrContext::PaintStageVertexLayoutBits(
121 const GrPaint& paint,
122 const bool hasTexCoords[GrPaint::kTotalStages]) {
123 int stageMask = paint.getActiveStageMask();
124 int layout = 0;
125 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
126 if ((1 << i) & stageMask) {
127 if (NULL != hasTexCoords && hasTexCoords[i]) {
128 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
129 } else {
130 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
131 }
132 }
133 }
134 return layout;
135}
136
137
138////////////////////////////////////////////////////////////////////////////////
139
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000140enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000141 // flags for textures
142 kNPOTBit = 0x1,
143 kFilterBit = 0x2,
144 kScratchBit = 0x4,
145
146 // resource type
147 kTextureBit = 0x8,
148 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000149};
150
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000151GrTexture* GrContext::TextureCacheEntry::texture() const {
152 if (NULL == fEntry) {
153 return NULL;
154 } else {
155 return (GrTexture*) fEntry->resource();
156 }
157}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000158
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000159namespace {
160// returns true if this is a "special" texture because of gpu NPOT limitations
161bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000162 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163 GrContext::TextureKey clientKey,
164 int width,
165 int height,
166 bool scratch,
167 uint32_t v[4]) {
168 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
169 // we assume we only need 16 bits of width and height
170 // assert that texture creation will fail anyway if this assumption
171 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000172 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000173 v[0] = clientKey & 0xffffffffUL;
174 v[1] = (clientKey >> 32) & 0xffffffffUL;
175 v[2] = width | (height << 16);
176
177 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000178 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
180
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000181 bool tiled = NULL != sampler &&
182 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
183 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184
185 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000187 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 }
190 }
191 }
192
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 if (scratch) {
194 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197 v[3] |= kTextureBit;
198
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199 return v[3] & kNPOTBit;
200}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000201
202// we should never have more than one stencil buffer with same combo of
203// (width,height,samplecount)
204void gen_stencil_key_values(int width, int height,
205 int sampleCnt, uint32_t v[4]) {
206 v[0] = width;
207 v[1] = height;
208 v[2] = sampleCnt;
209 v[3] = kStencilBufferBit;
210}
211
212void gen_stencil_key_values(const GrStencilBuffer* sb,
213 uint32_t v[4]) {
214 gen_stencil_key_values(sb->width(), sb->height(),
215 sb->numSamples(), v);
216}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000217
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000218}
219
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000220GrContext::TextureCacheEntry GrContext::findAndLockTexture(
221 TextureKey key,
222 int width,
223 int height,
224 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000225 uint32_t v[4];
226 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
227 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000228 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
229 GrResourceCache::kNested_LockType));
230}
231
bsalomon@google.comfb309512011-11-30 14:13:48 +0000232bool GrContext::isTextureInCache(TextureKey key,
233 int width,
234 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000235 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000236 uint32_t v[4];
237 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
238 GrResourceKey resourceKey(v);
239 return fTextureCache->hasKey(resourceKey);
240}
241
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000242GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000243 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000244 uint32_t v[4];
245 gen_stencil_key_values(sb, v);
246 GrResourceKey resourceKey(v);
247 return fTextureCache->createAndLock(resourceKey, sb);
248}
249
250GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
251 int sampleCnt) {
252 uint32_t v[4];
253 gen_stencil_key_values(width, height, sampleCnt, v);
254 GrResourceKey resourceKey(v);
255 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
256 GrResourceCache::kSingle_LockType);
257 if (NULL != entry) {
258 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
259 return sb;
260 } else {
261 return NULL;
262 }
263}
264
265void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000266 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000267 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000268}
269
270static void stretchImage(void* dst,
271 int dstW,
272 int dstH,
273 void* src,
274 int srcW,
275 int srcH,
276 int bpp) {
277 GrFixed dx = (srcW << 16) / dstW;
278 GrFixed dy = (srcH << 16) / dstH;
279
280 GrFixed y = dy >> 1;
281
282 int dstXLimit = dstW*bpp;
283 for (int j = 0; j < dstH; ++j) {
284 GrFixed x = dx >> 1;
285 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
286 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
287 for (int i = 0; i < dstXLimit; i += bpp) {
288 memcpy((uint8_t*) dstRow + i,
289 (uint8_t*) srcRow + (x>>16)*bpp,
290 bpp);
291 x += dx;
292 }
293 y += dy;
294 }
295}
296
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000297GrContext::TextureCacheEntry GrContext::createAndLockTexture(
298 TextureKey key,
299 const GrSamplerState* sampler,
300 const GrTextureDesc& desc,
301 void* srcData,
302 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000303 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000304
305#if GR_DUMP_TEXTURE_UPLOAD
306 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
307#endif
308
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000309 TextureCacheEntry entry;
310 uint32_t v[4];
311 bool special = gen_texture_key_values(fGpu, sampler, key,
312 desc.fWidth, desc.fHeight, false, v);
313 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000314
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000315 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000316 GrAssert(NULL != sampler);
317 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
318 desc.fWidth,
319 desc.fHeight,
320 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000321
322 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000323 clampEntry = this->createAndLockTexture(key, NULL, desc,
324 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000325 GrAssert(NULL != clampEntry.texture());
326 if (NULL == clampEntry.texture()) {
327 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000328 }
329 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000330 GrTextureDesc rtDesc = desc;
331 rtDesc.fFlags = rtDesc.fFlags |
332 kRenderTarget_GrTextureFlagBit |
333 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000334 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
335 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000336
337 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
338
339 if (NULL != texture) {
340 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000341 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000342 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000343 drawState->setRenderTarget(texture->asRenderTarget());
344 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000345
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000346 GrSamplerState::Filter filter;
347 // if filtering is not desired then we want to ensure all
348 // texels in the resampled image are copies of texels from
349 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000350 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000351 filter = GrSamplerState::kNearest_Filter;
352 } else {
353 filter = GrSamplerState::kBilinear_Filter;
354 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000355 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
356 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000357
358 static const GrVertexLayout layout =
359 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
360 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
361
362 if (arg.succeeded()) {
363 GrPoint* verts = (GrPoint*) arg.vertices();
364 verts[0].setIRectFan(0, 0,
365 texture->width(),
366 texture->height(),
367 2*sizeof(GrPoint));
368 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
369 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
370 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000371 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000372 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000373 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000374 } else {
375 // TODO: Our CPU stretch doesn't filter. But we create separate
376 // stretched textures when the sampler state is either filtered or
377 // not. Either implement filtered stretch blit on CPU or just create
378 // one when FBO case fails.
379
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000380 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000381 // no longer need to clamp at min RT size.
382 rtDesc.fWidth = GrNextPow2(desc.fWidth);
383 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000384 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000385 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000386 rtDesc.fWidth *
387 rtDesc.fHeight);
388 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
389 srcData, desc.fWidth, desc.fHeight, bpp);
390
391 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
392
393 GrTexture* texture = fGpu->createTexture(rtDesc,
394 stretchedPixels.get(),
395 stretchedRowBytes);
396 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000397 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000399 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000400
401 } else {
402 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
403 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000404 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000405 }
406 }
407 return entry;
408}
409
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000410namespace {
411inline void gen_scratch_tex_key_values(const GrGpu* gpu,
412 const GrTextureDesc& desc,
413 uint32_t v[4]) {
414 // Instead of a client-provided key of the texture contents
415 // we create a key of from the descriptor.
416 GrContext::TextureKey descKey = desc.fAALevel |
417 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000418 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000419 // this code path isn't friendly to tiling with NPOT restricitons
420 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000421 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
422 desc.fHeight, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000423}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000424}
425
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000426GrContext::TextureCacheEntry GrContext::lockScratchTexture(
427 const GrTextureDesc& inDesc,
428 ScratchTexMatch match) {
429
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000430 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000431 if (kExact_ScratchTexMatch != match) {
432 // bin by pow2 with a reasonable min
433 static const int MIN_SIZE = 256;
434 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
435 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
436 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000437
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000438 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000439 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
440
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000442 int origWidth = desc.fWidth;
443 int origHeight = desc.fHeight;
444 bool doubledW = false;
445 bool doubledH = false;
446
447 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000448 uint32_t v[4];
449 gen_scratch_tex_key_values(fGpu, desc, v);
450 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000451 entry = fTextureCache->findAndLock(key,
452 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000453 // if we miss, relax the fit of the flags...
454 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000455 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000456 break;
457 }
458 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
459 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
460 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
461 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
462 } else if (!doubledW) {
463 desc.fFlags = inDesc.fFlags;
464 desc.fWidth *= 2;
465 doubledW = true;
466 } else if (!doubledH) {
467 desc.fFlags = inDesc.fFlags;
468 desc.fWidth = origWidth;
469 desc.fHeight *= 2;
470 doubledH = true;
471 } else {
472 break;
473 }
474
475 } while (true);
476
477 if (NULL == entry) {
478 desc.fFlags = inDesc.fFlags;
479 desc.fWidth = origWidth;
480 desc.fHeight = origHeight;
481 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
482 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000483 uint32_t v[4];
484 gen_scratch_tex_key_values(fGpu, desc, v);
485 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000486 entry = fTextureCache->createAndLock(key, texture);
487 }
488 }
489
490 // If the caller gives us the same desc/sampler twice we don't want
491 // to return the same texture the second time (unless it was previously
492 // released). So we detach the entry from the cache and reattach at release.
493 if (NULL != entry) {
494 fTextureCache->detach(entry);
495 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000496 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000497}
498
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000499void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000500 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000501 // If this is a scratch texture we detached it from the cache
502 // while it was locked (to avoid two callers simultaneously getting
503 // the same texture).
504 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
505 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000506 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000507 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000508 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000509}
510
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000511GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000512 void* srcData,
513 size_t rowBytes) {
514 return fGpu->createTexture(desc, srcData, rowBytes);
515}
516
517void GrContext::getTextureCacheLimits(int* maxTextures,
518 size_t* maxTextureBytes) const {
519 fTextureCache->getLimits(maxTextures, maxTextureBytes);
520}
521
522void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
523 fTextureCache->setLimits(maxTextures, maxTextureBytes);
524}
525
bsalomon@google.com91958362011-06-13 17:58:13 +0000526int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000527 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000528}
529
530int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000531 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000532}
533
534///////////////////////////////////////////////////////////////////////////////
535
bsalomon@google.come269f212011-11-07 13:29:52 +0000536GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
537 return fGpu->createPlatformTexture(desc);
538}
539
540GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
541 return fGpu->createPlatformRenderTarget(desc);
542}
543
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000544GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
545 // validate flags here so that GrGpu subclasses don't have to check
546 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
547 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000548 return NULL;
549 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000550 if (desc.fSampleCnt &&
551 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000552 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000553 }
554 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
555 desc.fSampleCnt &&
556 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
557 return NULL;
558 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000559 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000560}
561
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000562///////////////////////////////////////////////////////////////////////////////
563
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000564bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000565 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000566 const GrDrawTarget::Caps& caps = fGpu->getCaps();
567 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000568 return false;
569 }
570
bsalomon@google.com27847de2011-02-22 20:59:41 +0000571 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
572
573 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000574 bool tiled = NULL != sampler &&
575 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
576 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000577 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000578 return false;
579 }
580 }
581 return true;
582}
583
584////////////////////////////////////////////////////////////////////////////////
585
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000586const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
587
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588void GrContext::setClip(const GrClip& clip) {
589 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000590 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000591}
592
593void GrContext::setClip(const GrIRect& rect) {
594 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000595 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596 fGpu->setClip(clip);
597}
598
599////////////////////////////////////////////////////////////////////////////////
600
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000601void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000602 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000603 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000604}
605
606void GrContext::drawPaint(const GrPaint& paint) {
607 // set rect to be big enough to fill the space, but not super-huge, so we
608 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000609 GrRect r;
610 r.setLTRB(0, 0,
611 GrIntToScalar(getRenderTarget()->width()),
612 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000613 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000614 SkTLazy<GrPaint> tmpPaint;
615 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000616 GrDrawState* drawState = fGpu->drawState();
617 GrAutoMatrix am;
618
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000619 // We attempt to map r by the inverse matrix and draw that. mapRect will
620 // map the four corners and bound them with a new rect. This will not
621 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000622 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000623 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000624 GrPrintf("Could not invert matrix");
625 return;
626 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000627 inverse.mapRect(&r);
628 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000629 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000630 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000631 GrPrintf("Could not invert matrix");
632 return;
633 }
634 tmpPaint.set(paint);
635 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
636 p = tmpPaint.get();
637 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000638 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000639 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000640 // by definition this fills the entire clip, no need for AA
641 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000642 if (!tmpPaint.isValid()) {
643 tmpPaint.set(paint);
644 p = tmpPaint.get();
645 }
646 GrAssert(p == tmpPaint.get());
647 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000648 }
649 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000650}
651
bsalomon@google.com205d4602011-04-25 12:43:45 +0000652////////////////////////////////////////////////////////////////////////////////
653
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000654namespace {
655inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
656 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
657}
658}
659
bsalomon@google.com91958362011-06-13 17:58:13 +0000660struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000661 enum Downsample {
bsalomon@google.com91958362011-06-13 17:58:13 +0000662 k4x4SinglePass_Downsample,
663 kFSAA_Downsample
664 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000665 int fTileSizeX;
666 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000667 int fTileCountX;
668 int fTileCountY;
669 int fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000670 GrAutoScratchTexture fOffscreen;
bsalomon@google.com91958362011-06-13 17:58:13 +0000671 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000672 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000673};
674
bsalomon@google.com471d4712011-08-23 15:45:25 +0000675bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000676 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000677#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000678 return false;
679#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000680 // Line primitves are always rasterized as 1 pixel wide.
681 // Super-sampling would make them too thin but MSAA would be OK.
682 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000683 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000684 return false;
685 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000686 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000687 return false;
688 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000689 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000690#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000691 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000692#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000693 return false;
694 }
695 return true;
696#endif
697}
698
bsalomon@google.com91958362011-06-13 17:58:13 +0000699bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000700 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000701 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000702 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000703 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000704
705 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000706
bsalomon@google.com46579e02012-01-11 18:51:15 +0000707 GrAssert(NULL == record->fOffscreen.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000708 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000709
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000710 int boundW = boundRect.width();
711 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000712
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000713 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000714
715 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
716 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
717
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000718 if (requireStencil) {
719 desc.fFlags = kRenderTarget_GrTextureFlagBit;
720 } else {
721 desc.fFlags = kRenderTarget_GrTextureFlagBit |
722 kNoStencil_GrTextureFlagBit;
723 }
724
bsalomon@google.comc4364992011-11-07 15:54:49 +0000725 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000726
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000727 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000728 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000729 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000730 desc.fAALevel = kMed_GrAALevel;
731 } else {
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000732 record->fDownsample = OffscreenRecord::k4x4SinglePass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000733 record->fScale = OFFSCREEN_SSAA_SCALE;
734 // both downsample paths assume this
735 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000736 desc.fAALevel = kNone_GrAALevel;
737 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000738
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000739 desc.fWidth *= record->fScale;
740 desc.fHeight *= record->fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000741 record->fOffscreen.set(this, desc);
742 if (NULL == record->fOffscreen.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000743 return false;
744 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000745 // the approximate lookup might have given us some slop space, might as well
746 // use it when computing the tiles size.
747 // these are scale values, will adjust after considering
748 // the possible second offscreen.
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000749 record->fTileSizeX = record->fOffscreen.texture()->width();
750 record->fTileSizeY = record->fOffscreen.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000751
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000752 record->fTileSizeX /= record->fScale;
753 record->fTileSizeY /= record->fScale;
754
755 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
756 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
757
tomhudson@google.com237a4612011-07-19 15:44:00 +0000758 record->fClip = target->getClip();
759
bsalomon@google.com91958362011-06-13 17:58:13 +0000760 target->saveCurrentDrawState(&record->fSavedState);
761 return true;
762}
763
764void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
765 const GrIRect& boundRect,
766 int tileX, int tileY,
767 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000769 GrRenderTarget* offRT = record->fOffscreen.texture()->asRenderTarget();
770 GrAssert(NULL != offRT);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000771
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000772
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000773 GrDrawState* drawState = target->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000774 GrMatrix vm = drawState->getViewMatrix();
775 drawState->reset();
776 *drawState->viewMatrix() = vm;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000777 drawState->setRenderTarget(offRT);
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000778
bsalomon@google.com289533a2011-10-27 12:34:25 +0000779#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com337af172012-01-11 16:00:42 +0000780 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000781#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000782
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000783 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000784 int left = boundRect.fLeft + tileX * record->fTileSizeX;
785 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000786 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000787 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000788 GrMatrix scaleM;
789 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000790 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000791
bsalomon@google.com91958362011-06-13 17:58:13 +0000792 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000793 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000794 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000795 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000796 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
797 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000798 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000799#if 0
800 // visualize tile boundaries by setting edges of offscreen to white
801 // and interior to tranparent. black.
802 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000803
bsalomon@google.com91958362011-06-13 17:58:13 +0000804 static const int gOffset = 2;
805 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
806 record->fScale * w - gOffset,
807 record->fScale * h - gOffset);
808 target->clear(&clear2, 0x0);
809#else
810 target->clear(&clear, 0x0);
811#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000812}
813
bsalomon@google.com91958362011-06-13 17:58:13 +0000814void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000815 const GrPaint& paint,
816 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000817 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000818 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000819 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com46579e02012-01-11 18:51:15 +0000820 GrAssert(NULL != record->fOffscreen.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000821 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000822 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000823 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
824 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000825 tileRect.fRight = (tileX == record->fTileCountX-1) ?
826 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000827 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000828 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
829 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000830 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000831
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000832 GrSamplerState::Filter filter;
833 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
834 filter = GrSamplerState::k4x4Downsample_Filter;
835 } else {
836 filter = GrSamplerState::kBilinear_Filter;
837 }
838
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000839 GrTexture* src = record->fOffscreen.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000840 int scale;
841
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000842 enum {
843 kOffscreenStage = GrPaint::kTotalStages,
844 };
845
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000846 GrDrawState* drawState = target->drawState();
847
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000848 if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000849 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000850 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000852 } else {
853 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
854 record->fDownsample);
855 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000856 }
857
bsalomon@google.com91958362011-06-13 17:58:13 +0000858 // setup for draw back to main RT, we use the original
859 // draw state setup by the caller plus an additional coverage
860 // stage to handle the AA resolve. Also, we use an identity
861 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000862 int stageMask = paint.getActiveStageMask();
863
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000865 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000866
867 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000868 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000869 if (drawState->getViewInverse(&invVM)) {
870 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871 }
872 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000873 // This is important when tiling, otherwise second tile's
874 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000875 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000876
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000877 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000878 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
879 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000880 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
881 scale * GR_Scalar1 / src->height());
882 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
883 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000884
reed@google.com20efde72011-05-09 17:00:02 +0000885 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000886 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000887 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000888 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000889}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000890
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000891void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
892 GrPathRenderer* pr,
893 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000894 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000895}
896
897////////////////////////////////////////////////////////////////////////////////
898
bsalomon@google.com27847de2011-02-22 20:59:41 +0000899/* create a triangle strip that strokes the specified triangle. There are 8
900 unique vertices, but we repreat the last 2 to close up. Alternatively we
901 could use an indices array, and then only send 8 verts, but not sure that
902 would be faster.
903 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000904static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000905 GrScalar width) {
906 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000907 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000908
909 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
910 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
911 verts[2].set(rect.fRight - rad, rect.fTop + rad);
912 verts[3].set(rect.fRight + rad, rect.fTop - rad);
913 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
914 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
915 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
916 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
917 verts[8] = verts[0];
918 verts[9] = verts[1];
919}
920
bsalomon@google.com205d4602011-04-25 12:43:45 +0000921static void setInsetFan(GrPoint* pts, size_t stride,
922 const GrRect& r, GrScalar dx, GrScalar dy) {
923 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
924}
925
926static const uint16_t gFillAARectIdx[] = {
927 0, 1, 5, 5, 4, 0,
928 1, 2, 6, 6, 5, 1,
929 2, 3, 7, 7, 6, 2,
930 3, 0, 4, 4, 7, 3,
931 4, 5, 6, 6, 7, 4,
932};
933
934int GrContext::aaFillRectIndexCount() const {
935 return GR_ARRAY_COUNT(gFillAARectIdx);
936}
937
938GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
939 if (NULL == fAAFillRectIndexBuffer) {
940 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
941 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000942 if (NULL != fAAFillRectIndexBuffer) {
943 #if GR_DEBUG
944 bool updated =
945 #endif
946 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
947 sizeof(gFillAARectIdx));
948 GR_DEBUGASSERT(updated);
949 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000950 }
951 return fAAFillRectIndexBuffer;
952}
953
954static const uint16_t gStrokeAARectIdx[] = {
955 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
956 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
957 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
958 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
959
960 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
961 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
962 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
963 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
964
965 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
966 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
967 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
968 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
969};
970
971int GrContext::aaStrokeRectIndexCount() const {
972 return GR_ARRAY_COUNT(gStrokeAARectIdx);
973}
974
975GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
976 if (NULL == fAAStrokeRectIndexBuffer) {
977 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
978 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000979 if (NULL != fAAStrokeRectIndexBuffer) {
980 #if GR_DEBUG
981 bool updated =
982 #endif
983 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
984 sizeof(gStrokeAARectIdx));
985 GR_DEBUGASSERT(updated);
986 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000987 }
988 return fAAStrokeRectIndexBuffer;
989}
990
bsalomon@google.coma3108262011-10-10 14:08:47 +0000991static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
992 bool useCoverage) {
993 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000994 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000995 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000996 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
997 }
998 }
999 if (useCoverage) {
1000 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1001 } else {
1002 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1003 }
1004 return layout;
1005}
1006
bsalomon@google.com205d4602011-04-25 12:43:45 +00001007void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001008 const GrRect& devRect,
1009 bool useVertexCoverage) {
1010 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001011
1012 size_t vsize = GrDrawTarget::VertexSize(layout);
1013
1014 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001015 if (!geo.succeeded()) {
1016 GrPrintf("Failed to get space for vertices!\n");
1017 return;
1018 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001019 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1020 if (NULL == indexBuffer) {
1021 GrPrintf("Failed to create index buffer!\n");
1022 return;
1023 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001024
1025 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1026
1027 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1028 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1029
1030 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1031 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1032
1033 verts += sizeof(GrPoint);
1034 for (int i = 0; i < 4; ++i) {
1035 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1036 }
1037
bsalomon@google.coma3108262011-10-10 14:08:47 +00001038 GrColor innerColor;
1039 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001040 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001041 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001042 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001043 }
1044
bsalomon@google.com205d4602011-04-25 12:43:45 +00001045 verts += 4 * vsize;
1046 for (int i = 0; i < 4; ++i) {
1047 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1048 }
1049
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001050 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001051
1052 target->drawIndexed(kTriangles_PrimitiveType, 0,
1053 0, 8, this->aaFillRectIndexCount());
1054}
1055
bsalomon@google.coma3108262011-10-10 14:08:47 +00001056void GrContext::strokeAARect(GrDrawTarget* target,
1057 const GrRect& devRect,
1058 const GrVec& devStrokeSize,
1059 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001060 const GrScalar& dx = devStrokeSize.fX;
1061 const GrScalar& dy = devStrokeSize.fY;
1062 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1063 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1064
bsalomon@google.com205d4602011-04-25 12:43:45 +00001065 GrScalar spare;
1066 {
1067 GrScalar w = devRect.width() - dx;
1068 GrScalar h = devRect.height() - dy;
1069 spare = GrMin(w, h);
1070 }
1071
1072 if (spare <= 0) {
1073 GrRect r(devRect);
1074 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001075 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001076 return;
1077 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001078 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001079 size_t vsize = GrDrawTarget::VertexSize(layout);
1080
1081 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001082 if (!geo.succeeded()) {
1083 GrPrintf("Failed to get space for vertices!\n");
1084 return;
1085 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001086 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1087 if (NULL == indexBuffer) {
1088 GrPrintf("Failed to create index buffer!\n");
1089 return;
1090 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001091
1092 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1093
1094 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1095 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1096 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1097 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1098
1099 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1100 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1101 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1102 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1103
1104 verts += sizeof(GrPoint);
1105 for (int i = 0; i < 4; ++i) {
1106 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1107 }
1108
bsalomon@google.coma3108262011-10-10 14:08:47 +00001109 GrColor innerColor;
1110 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001111 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001112 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001113 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001114 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001115 verts += 4 * vsize;
1116 for (int i = 0; i < 8; ++i) {
1117 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1118 }
1119
1120 verts += 8 * vsize;
1121 for (int i = 0; i < 8; ++i) {
1122 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1123 }
1124
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001125 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001126 target->drawIndexed(kTriangles_PrimitiveType,
1127 0, 0, 16, aaStrokeRectIndexCount());
1128}
1129
reed@google.com20efde72011-05-09 17:00:02 +00001130/**
1131 * Returns true if the rects edges are integer-aligned.
1132 */
1133static bool isIRect(const GrRect& r) {
1134 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1135 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1136}
1137
bsalomon@google.com205d4602011-04-25 12:43:45 +00001138static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001139 const GrRect& rect,
1140 GrScalar width,
1141 const GrMatrix* matrix,
1142 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001143 GrRect* devRect,
1144 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001145 // we use a simple coverage ramp to do aa on axis-aligned rects
1146 // we check if the rect will be axis-aligned, and the rect won't land on
1147 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001148
bsalomon@google.coma3108262011-10-10 14:08:47 +00001149 // we are keeping around the "tweak the alpha" trick because
1150 // it is our only hope for the fixed-pipe implementation.
1151 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001152 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001153 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001154 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001155 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001156#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001157 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001158#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001159 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001160 } else {
1161 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001162 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001163 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001164 const GrDrawState& drawState = target->getDrawState();
1165 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001166 return false;
1167 }
1168
bsalomon@google.com471d4712011-08-23 15:45:25 +00001169 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001170 return false;
1171 }
1172
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001173 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001174 return false;
1175 }
1176
1177 if (NULL != matrix &&
1178 !matrix->preservesAxisAlignment()) {
1179 return false;
1180 }
1181
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001182 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001183 if (NULL != matrix) {
1184 combinedMatrix->preConcat(*matrix);
1185 GrAssert(combinedMatrix->preservesAxisAlignment());
1186 }
1187
1188 combinedMatrix->mapRect(devRect, rect);
1189 devRect->sort();
1190
1191 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001192 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001193 } else {
1194 return true;
1195 }
1196}
1197
bsalomon@google.com27847de2011-02-22 20:59:41 +00001198void GrContext::drawRect(const GrPaint& paint,
1199 const GrRect& rect,
1200 GrScalar width,
1201 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001202 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001203
1204 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001205 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001206
bsalomon@google.com205d4602011-04-25 12:43:45 +00001207 GrRect devRect = rect;
1208 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001209 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001210 bool needAA = paint.fAntiAlias &&
1211 !this->getRenderTarget()->isMultisampled();
1212 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1213 &combinedMatrix, &devRect,
1214 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001215
1216 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001217 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001218 if (width >= 0) {
1219 GrVec strokeSize;;
1220 if (width > 0) {
1221 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001222 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001223 strokeSize.setAbs(strokeSize);
1224 } else {
1225 strokeSize.set(GR_Scalar1, GR_Scalar1);
1226 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001227 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001228 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001229 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001230 }
1231 return;
1232 }
1233
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234 if (width >= 0) {
1235 // TODO: consider making static vertex buffers for these cases.
1236 // Hairline could be done by just adding closing vertex to
1237 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001238 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1239
bsalomon@google.com27847de2011-02-22 20:59:41 +00001240 static const int worstCaseVertCount = 10;
1241 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1242
1243 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001244 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001245 return;
1246 }
1247
1248 GrPrimitiveType primType;
1249 int vertCount;
1250 GrPoint* vertex = geo.positions();
1251
1252 if (width > 0) {
1253 vertCount = 10;
1254 primType = kTriangleStrip_PrimitiveType;
1255 setStrokeRectStrip(vertex, rect, width);
1256 } else {
1257 // hairline
1258 vertCount = 5;
1259 primType = kLineStrip_PrimitiveType;
1260 vertex[0].set(rect.fLeft, rect.fTop);
1261 vertex[1].set(rect.fRight, rect.fTop);
1262 vertex[2].set(rect.fRight, rect.fBottom);
1263 vertex[3].set(rect.fLeft, rect.fBottom);
1264 vertex[4].set(rect.fLeft, rect.fTop);
1265 }
1266
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001267 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001268 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001269 GrDrawState* drawState = target->drawState();
1270 avmr.set(drawState);
1271 drawState->preConcatViewMatrix(*matrix);
1272 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001273 }
1274
1275 target->drawNonIndexed(primType, 0, vertCount);
1276 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001277#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001278 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001279 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1280 if (NULL == sqVB) {
1281 GrPrintf("Failed to create static rect vb.\n");
1282 return;
1283 }
1284 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001285 GrDrawState* drawState = target->drawState();
1286 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001288 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001289 0, rect.height(), rect.fTop,
1290 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001291
1292 if (NULL != matrix) {
1293 m.postConcat(*matrix);
1294 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001295 drawState->preConcatViewMatrix(m);
1296 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001297
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001299#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001300 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001301#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001302 }
1303}
1304
1305void GrContext::drawRectToRect(const GrPaint& paint,
1306 const GrRect& dstRect,
1307 const GrRect& srcRect,
1308 const GrMatrix* dstMatrix,
1309 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001310 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001311
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001312 // srcRect refers to paint's first texture
1313 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314 drawRect(paint, dstRect, -1, dstMatrix);
1315 return;
1316 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001317
bsalomon@google.com27847de2011-02-22 20:59:41 +00001318 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1319
1320#if GR_STATIC_RECT_VB
1321 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001322 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001323 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001324 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001325
1326 GrMatrix m;
1327
1328 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1329 0, dstRect.height(), dstRect.fTop,
1330 0, 0, GrMatrix::I()[8]);
1331 if (NULL != dstMatrix) {
1332 m.postConcat(*dstMatrix);
1333 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001334 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001335
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001336 // srcRect refers to first stage
1337 int otherStageMask = paint.getActiveStageMask() &
1338 (~(1 << GrPaint::kFirstTextureStage));
1339 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001340 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001341 }
1342
bsalomon@google.com27847de2011-02-22 20:59:41 +00001343 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1344 0, srcRect.height(), srcRect.fTop,
1345 0, 0, GrMatrix::I()[8]);
1346 if (NULL != srcMatrix) {
1347 m.postConcat(*srcMatrix);
1348 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001349 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001350
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001351 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1352 if (NULL == sqVB) {
1353 GrPrintf("Failed to create static rect vb.\n");
1354 return;
1355 }
1356 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001357 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1358#else
1359
1360 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001361#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001362 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001363#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001364 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1365#endif
1366
tomhudson@google.com93813632011-10-27 20:21:16 +00001367 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1368 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001369 srcRects[0] = &srcRect;
1370 srcMatrices[0] = srcMatrix;
1371
1372 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1373#endif
1374}
1375
1376void GrContext::drawVertices(const GrPaint& paint,
1377 GrPrimitiveType primitiveType,
1378 int vertexCount,
1379 const GrPoint positions[],
1380 const GrPoint texCoords[],
1381 const GrColor colors[],
1382 const uint16_t indices[],
1383 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001384 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001385
1386 GrDrawTarget::AutoReleaseGeometry geo;
1387
1388 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1389
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001390 bool hasTexCoords[GrPaint::kTotalStages] = {
1391 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1392 0 // remaining stages use positions
1393 };
1394
1395 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001396
1397 if (NULL != colors) {
1398 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001399 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001400 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001401
1402 if (sizeof(GrPoint) != vertexSize) {
1403 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001404 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405 return;
1406 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001407 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001408 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001409 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1410 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001411 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001412 NULL,
1413 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001414 void* curVertex = geo.vertices();
1415
1416 for (int i = 0; i < vertexCount; ++i) {
1417 *((GrPoint*)curVertex) = positions[i];
1418
1419 if (texOffsets[0] > 0) {
1420 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1421 }
1422 if (colorOffset > 0) {
1423 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1424 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001425 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001426 }
1427 } else {
1428 target->setVertexSourceToArray(layout, positions, vertexCount);
1429 }
1430
bsalomon@google.com91958362011-06-13 17:58:13 +00001431 // we don't currently apply offscreen AA to this path. Need improved
1432 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001433
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001434 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001435 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001436 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001437 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001438 target->drawNonIndexed(primitiveType, 0, vertexCount);
1439 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001440}
1441
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001442///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001443#include "SkDraw.h"
1444#include "SkRasterClip.h"
1445
1446namespace {
1447
1448SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1449 switch (fill) {
1450 case kWinding_PathFill:
1451 return SkPath::kWinding_FillType;
1452 case kEvenOdd_PathFill:
1453 return SkPath::kEvenOdd_FillType;
1454 case kInverseWinding_PathFill:
1455 return SkPath::kInverseWinding_FillType;
1456 case kInverseEvenOdd_PathFill:
1457 return SkPath::kInverseEvenOdd_FillType;
1458 default:
1459 GrCrash("Unexpected fill.");
1460 return SkPath::kWinding_FillType;
1461 }
1462}
1463
1464// gets device coord bounds of path (not considering the fill) and clip. The
1465// path bounds will be a subset of the clip bounds. returns false if path bounds
1466// would be empty.
1467bool get_path_and_clip_bounds(const GrDrawTarget* target,
1468 const GrPath& path,
1469 const GrVec* translate,
1470 GrIRect* pathBounds,
1471 GrIRect* clipBounds) {
1472 // compute bounds as intersection of rt size, clip, and path
1473 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1474 if (NULL == rt) {
1475 return false;
1476 }
1477 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1478 const GrClip& clip = target->getClip();
1479 if (clip.hasConservativeBounds()) {
1480 clip.getConservativeBounds().roundOut(clipBounds);
1481 if (!pathBounds->intersect(*clipBounds)) {
1482 return false;
1483 }
1484 } else {
1485 // pathBounds is currently the rt extent, set clip bounds to that rect.
1486 *clipBounds = *pathBounds;
1487 }
1488 GrRect pathSBounds = path.getBounds();
1489 if (!pathSBounds.isEmpty()) {
1490 if (NULL != translate) {
1491 pathSBounds.offset(*translate);
1492 }
1493 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1494 pathSBounds);
1495 GrIRect pathIBounds;
1496 pathSBounds.roundOut(&pathIBounds);
1497 if (!pathBounds->intersect(pathIBounds)) {
1498 return false;
1499 }
1500 } else {
1501 return false;
1502 }
1503 return true;
1504}
1505
1506/**
1507 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1508 * scratch texture.
1509 */
1510
1511bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1512 const GrIRect& pathDevBounds,
1513 GrPathFill fill,
1514 GrContext* context,
1515 const GrPoint* translate,
1516 GrAutoScratchTexture* tex) {
1517 SkPaint paint;
1518 SkPath tmpPath;
1519 const SkPath* pathToDraw = &clientPath;
1520 if (kHairLine_PathFill == fill) {
1521 paint.setStyle(SkPaint::kStroke_Style);
1522 paint.setStrokeWidth(SK_Scalar1);
1523 } else {
1524 paint.setStyle(SkPaint::kFill_Style);
1525 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1526 if (skfill != pathToDraw->getFillType()) {
1527 tmpPath = *pathToDraw;
1528 tmpPath.setFillType(skfill);
1529 pathToDraw = &tmpPath;
1530 }
1531 }
1532 paint.setAntiAlias(true);
1533 paint.setColor(SK_ColorWHITE);
1534
1535 GrMatrix matrix = context->getMatrix();
1536 if (NULL != translate) {
1537 matrix.postTranslate(translate->fX, translate->fY);
1538 }
1539
1540 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1541 -pathDevBounds.fTop * SK_Scalar1);
1542 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1543 pathDevBounds.height());
1544
1545 SkBitmap bm;
1546 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1547 if (!bm.allocPixels()) {
1548 return false;
1549 }
1550 sk_bzero(bm.getPixels(), bm.getSafeSize());
1551
1552 SkDraw draw;
1553 sk_bzero(&draw, sizeof(draw));
1554 SkRasterClip rc(bounds);
1555 draw.fRC = &rc;
1556 draw.fClip = &rc.bwRgn();
1557 draw.fMatrix = &matrix;
1558 draw.fBitmap = &bm;
1559 draw.drawPath(*pathToDraw, paint);
1560
1561 const GrTextureDesc desc = {
1562 kNone_GrTextureFlags,
1563 kNone_GrAALevel,
1564 bounds.fRight,
1565 bounds.fBottom,
1566 kAlpha_8_GrPixelConfig
1567 };
1568
1569 tex->set(context, desc);
1570 GrTexture* texture = tex->texture();
1571
1572 if (NULL == texture) {
1573 return false;
1574 }
1575 SkAutoLockPixels alp(bm);
1576 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1577 bm.getPixels(), bm.rowBytes());
1578 return true;
1579}
1580
1581void draw_around_inv_path(GrDrawTarget* target,
1582 GrDrawState::StageMask stageMask,
1583 const GrIRect& clipBounds,
1584 const GrIRect& pathBounds) {
1585 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1586 GrRect rect;
1587 if (clipBounds.fTop < pathBounds.fTop) {
1588 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1589 clipBounds.fRight, pathBounds.fTop);
1590 target->drawSimpleRect(rect, NULL, stageMask);
1591 }
1592 if (clipBounds.fLeft < pathBounds.fLeft) {
1593 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1594 pathBounds.fLeft, pathBounds.fBottom);
1595 target->drawSimpleRect(rect, NULL, stageMask);
1596 }
1597 if (clipBounds.fRight > pathBounds.fRight) {
1598 rect.iset(pathBounds.fRight, pathBounds.fTop,
1599 clipBounds.fRight, pathBounds.fBottom);
1600 target->drawSimpleRect(rect, NULL, stageMask);
1601 }
1602 if (clipBounds.fBottom > pathBounds.fBottom) {
1603 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1604 clipBounds.fRight, clipBounds.fBottom);
1605 target->drawSimpleRect(rect, NULL, stageMask);
1606 }
1607}
1608
1609}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001610
reed@google.com07f3ee12011-05-16 17:21:57 +00001611void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1612 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001613
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001614 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001615 if (GrIsFillInverted(fill)) {
1616 this->drawPaint(paint);
1617 }
1618 return;
1619 }
1620
bsalomon@google.com27847de2011-02-22 20:59:41 +00001621 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001622 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001623
bsalomon@google.com289533a2011-10-27 12:34:25 +00001624 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1625
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001626 // An Assumption here is that path renderer would use some form of tweaking
1627 // the src color (either the input alpha or in the frag shader) to implement
1628 // aa. If we have some future driver-mojo path AA that can do the right
1629 // thing WRT to the blend then we'll need some query on the PR.
1630 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001631#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001632 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001633#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001634 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001635 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001636
1637 bool doOSAA = false;
1638 GrPathRenderer* pr = NULL;
1639 if (prAA) {
1640 pr = this->getPathRenderer(path, fill, true);
1641 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001642 GrAutoScratchTexture ast;
1643 GrIRect pathBounds, clipBounds;
1644 if (!get_path_and_clip_bounds(target, path, translate,
1645 &pathBounds, &clipBounds)) {
1646 return;
1647 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001648 prAA = false;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001649 if (this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
1650 pr = this->getPathRenderer(path, fill, false);
1651 doOSAA = true;
1652 }
1653 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1654 fill, this,
1655 translate, &ast)) {
1656 GrTexture* texture = ast.texture();
1657 GrAssert(NULL != texture);
1658 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1659 enum {
1660 kPathMaskStage = GrPaint::kTotalStages,
1661 };
1662 target->drawState()->setTexture(kPathMaskStage, texture);
1663 target->drawState()->sampler(kPathMaskStage)->reset();
1664 GrScalar w = GrIntToScalar(pathBounds.width());
1665 GrScalar h = GrIntToScalar(pathBounds.height());
1666 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1667 h / texture->height());
1668 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1669 srcRects[kPathMaskStage] = &maskRect;
1670 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001671 GrRect dstRect = GrRect::MakeLTRB(
1672 SK_Scalar1* pathBounds.fLeft,
1673 SK_Scalar1* pathBounds.fTop,
1674 SK_Scalar1* pathBounds.fRight,
1675 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001676 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1677 target->drawState()->setTexture(kPathMaskStage, NULL);
1678 if (GrIsFillInverted(fill)) {
1679 draw_around_inv_path(target, stageMask,
1680 clipBounds, pathBounds);
1681 }
1682 return;
1683 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001684 }
1685 } else {
1686 pr = this->getPathRenderer(path, fill, false);
1687 }
1688
bsalomon@google.com30085192011-08-19 15:42:31 +00001689 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001690#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001691 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001692#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001693 return;
1694 }
1695
bsalomon@google.com289533a2011-10-27 12:34:25 +00001696 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001697
bsalomon@google.com289533a2011-10-27 12:34:25 +00001698 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001699 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001700 GrIRect pathBounds;
1701 GrIRect clipBounds;
1702 if (!get_path_and_clip_bounds(target, path, translate,
1703 &pathBounds, &clipBounds)) {
1704 return;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001705 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001706 OffscreenRecord record;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001707 if (this->prepareForOffscreenAA(target, needsStencil, pathBounds,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001708 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001709 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1710 for (int ty = 0; ty < record.fTileCountY; ++ty) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001711 this->setupOffscreenAAPass1(target, pathBounds,
1712 tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001713 pr->drawPath(0);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001714 this->doOffscreenAAPass2(target, paint, pathBounds,
1715 tx, ty, &record);
bsalomon@google.com91958362011-06-13 17:58:13 +00001716 }
1717 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001718 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001719 if (GrIsFillInverted(fill)) {
1720 draw_around_inv_path(target, stageMask, clipBounds, pathBounds);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001721 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001722 return;
1723 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001724 }
1725 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001726}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001727
bsalomon@google.com27847de2011-02-22 20:59:41 +00001728////////////////////////////////////////////////////////////////////////////////
1729
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001730void GrContext::flush(int flagsBitfield) {
1731 if (kDiscard_FlushBit & flagsBitfield) {
1732 fDrawBuffer->reset();
1733 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001734 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001735 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001736 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001737 fGpu->forceRenderTargetFlush();
1738 }
1739}
1740
1741void GrContext::flushText() {
1742 if (kText_DrawCategory == fLastDrawCategory) {
1743 flushDrawBuffer();
1744 }
1745}
1746
1747void GrContext::flushDrawBuffer() {
1748#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001749 if (fDrawBuffer) {
1750 fDrawBuffer->playback(fGpu);
1751 fDrawBuffer->reset();
1752 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001753#endif
1754}
1755
bsalomon@google.com6f379512011-11-16 20:36:03 +00001756void GrContext::internalWriteTexturePixels(GrTexture* texture,
1757 int left, int top,
1758 int width, int height,
1759 GrPixelConfig config,
1760 const void* buffer,
1761 size_t rowBytes,
1762 uint32_t flags) {
1763 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001764 ASSERT_OWNED_RESOURCE(texture);
1765
bsalomon@google.com6f379512011-11-16 20:36:03 +00001766 if (!(kDontFlush_PixelOpsFlag & flags)) {
1767 this->flush();
1768 }
1769 // TODO: use scratch texture to perform conversion
1770 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1771 GrPixelConfigIsUnpremultiplied(config)) {
1772 return;
1773 }
1774
1775 fGpu->writeTexturePixels(texture, left, top, width, height,
1776 config, buffer, rowBytes);
1777}
1778
1779bool GrContext::internalReadTexturePixels(GrTexture* texture,
1780 int left, int top,
1781 int width, int height,
1782 GrPixelConfig config,
1783 void* buffer,
1784 size_t rowBytes,
1785 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001786 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001787 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001788
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001789 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001790 GrRenderTarget* target = texture->asRenderTarget();
1791 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001792 return this->internalReadRenderTargetPixels(target,
1793 left, top, width, height,
1794 config, buffer, rowBytes,
1795 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001796 } else {
1797 return false;
1798 }
1799}
1800
bsalomon@google.com6f379512011-11-16 20:36:03 +00001801bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1802 int left, int top,
1803 int width, int height,
1804 GrPixelConfig config,
1805 void* buffer,
1806 size_t rowBytes,
1807 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001808 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001809 ASSERT_OWNED_RESOURCE(target);
1810
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001811 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001812 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001813 if (NULL == target) {
1814 return false;
1815 }
1816 }
1817
1818 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1819 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1820 // not supported at this time.
1821 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1822 !GrPixelConfigIsUnpremultiplied(config)) {
1823 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001824 }
1825
bsalomon@google.com6f379512011-11-16 20:36:03 +00001826 if (!(kDontFlush_PixelOpsFlag & flags)) {
1827 this->flush();
1828 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001829
1830 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001831 bool swapRAndB = NULL != src &&
1832 fGpu->preferredReadPixelsConfig(config) ==
1833 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001834
1835 bool flipY = NULL != src &&
1836 fGpu->readPixelsWillPayForYFlip(target, left, top,
1837 width, height, config,
1838 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001839 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1840 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001841
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001842 if (NULL == src && alphaConversion) {
1843 // we should fallback to cpu conversion here. This could happen when
1844 // we were given an external render target by the client that is not
1845 // also a texture (e.g. FBO 0 in GL)
1846 return false;
1847 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001848 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001849 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001850 if (flipY || swapRAndB || alphaConversion) {
1851 GrAssert(NULL != src);
1852 if (swapRAndB) {
1853 config = GrPixelConfigSwapRAndB(config);
1854 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001855 }
1856 // Make the scratch a render target because we don't have a robust
1857 // readTexturePixels as of yet (it calls this function).
1858 const GrTextureDesc desc = {
1859 kRenderTarget_GrTextureFlagBit,
1860 kNone_GrAALevel,
1861 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001862 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001863 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001864
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001865 // When a full readback is faster than a partial we could always make
1866 // the scratch exactly match the passed rect. However, if we see many
1867 // different size rectangles we will trash our texture cache and pay the
1868 // cost of creating and destroying many textures. So, we only request
1869 // an exact match when the caller is reading an entire RT.
1870 ScratchTexMatch match = kApprox_ScratchTexMatch;
1871 if (0 == left &&
1872 0 == top &&
1873 target->width() == width &&
1874 target->height() == height &&
1875 fGpu->fullReadPixelsIsFasterThanPartial()) {
1876 match = kExact_ScratchTexMatch;
1877 }
1878 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001879 GrTexture* texture = ast.texture();
1880 if (!texture) {
1881 return false;
1882 }
1883 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001884 GrAssert(NULL != target);
1885
1886 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001887 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001888 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001889 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001890
bsalomon@google.comc4364992011-11-07 15:54:49 +00001891 GrMatrix matrix;
1892 if (flipY) {
1893 matrix.setTranslate(SK_Scalar1 * left,
1894 SK_Scalar1 * (top + height));
1895 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1896 } else {
1897 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1898 }
1899 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001900 drawState->sampler(0)->reset(matrix);
1901 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001902 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001903 GrRect rect;
1904 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1905 fGpu->drawSimpleRect(rect, NULL, 0x1);
1906 left = 0;
1907 top = 0;
1908 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001909 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001910 left, top, width, height,
1911 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001912}
1913
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001914void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1915 if (NULL == src || NULL == dst) {
1916 return;
1917 }
1918 ASSERT_OWNED_RESOURCE(src);
1919
1920 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001921 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001922 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001923 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001924 GrMatrix sampleM;
1925 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001926 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001927 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001928 SkRect rect = SkRect::MakeXYWH(0, 0,
1929 SK_Scalar1 * src->width(),
1930 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001931 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1932}
1933
bsalomon@google.com6f379512011-11-16 20:36:03 +00001934void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1935 int left, int top,
1936 int width, int height,
1937 GrPixelConfig config,
1938 const void* buffer,
1939 size_t rowBytes,
1940 uint32_t flags) {
1941 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001942 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001943
1944 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001945 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001946 if (NULL == target) {
1947 return;
1948 }
1949 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001950
1951 // TODO: when underlying api has a direct way to do this we should use it
1952 // (e.g. glDrawPixels on desktop GL).
1953
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001954 // If the RT is also a texture and we don't have to do PM/UPM conversion
1955 // then take the texture path, which we expect to be at least as fast or
1956 // faster since it doesn't use an intermediate texture as we do below.
1957
1958#if !GR_MAC_BUILD
1959 // At least some drivers on the Mac get confused when glTexImage2D is called
1960 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1961 // determine what OS versions and/or HW is affected.
1962 if (NULL != target->asTexture() &&
1963 GrPixelConfigIsUnpremultiplied(target->config()) ==
1964 GrPixelConfigIsUnpremultiplied(config)) {
1965
1966 this->internalWriteTexturePixels(target->asTexture(),
1967 left, top, width, height,
1968 config, buffer, rowBytes, flags);
1969 return;
1970 }
1971#endif
1972
1973 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1974 GrPixelConfigSwapRAndB(config);
1975 if (swapRAndB) {
1976 config = GrPixelConfigSwapRAndB(config);
1977 }
1978
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001979 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001980 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001981 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001982 GrAutoScratchTexture ast(this, desc);
1983 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001984 if (NULL == texture) {
1985 return;
1986 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001987 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1988 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001989
bsalomon@google.com27847de2011-02-22 20:59:41 +00001990 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001991 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001992 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993
1994 GrMatrix matrix;
1995 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001996 drawState->setViewMatrix(matrix);
1997 drawState->setRenderTarget(target);
1998 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001999
bsalomon@google.com5c638652011-07-18 19:31:59 +00002000 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002001 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2002 GrSamplerState::kNearest_Filter,
2003 matrix);
2004 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002005
2006 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
2007 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002008 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00002009 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
2010 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002011 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00002012 return;
2013 }
2014 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
2015 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
2016}
2017////////////////////////////////////////////////////////////////////////////////
2018
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002019void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002020 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002021
2022 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
2023 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002024 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002025 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002026 if (paint.getTexture(i)) {
2027 *drawState->sampler(s) = paint.getTextureSampler(i);
2028 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002029 }
2030
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002031 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002032
2033 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
2034 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002035 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002036 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002037 if (paint.getMask(i)) {
2038 *drawState->sampler(s) = paint.getMaskSampler(i);
2039 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002040 }
2041
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002042 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002043
2044 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002045 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002046 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002047 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002048 }
2049 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002050 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002051 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002052 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002053 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002054 if (paint.fColorMatrixEnabled) {
2055 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
2056 } else {
2057 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
2058 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002059 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002060 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002061 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00002062
2063 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
2064 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
2065 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002066}
2067
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002068GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002069 DrawCategory category) {
2070 if (category != fLastDrawCategory) {
2071 flushDrawBuffer();
2072 fLastDrawCategory = category;
2073 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002074 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002075 GrDrawTarget* target = fGpu;
2076 switch (category) {
2077 case kText_DrawCategory:
2078#if DEFER_TEXT_RENDERING
2079 target = fDrawBuffer;
2080 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2081#else
2082 target = fGpu;
2083#endif
2084 break;
2085 case kUnbuffered_DrawCategory:
2086 target = fGpu;
2087 break;
2088 case kBuffered_DrawCategory:
2089 target = fDrawBuffer;
2090 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2091 break;
2092 }
2093 return target;
2094}
2095
bsalomon@google.com289533a2011-10-27 12:34:25 +00002096GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
2097 GrPathFill fill,
2098 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00002099 if (NULL == fPathRendererChain) {
2100 fPathRendererChain =
2101 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
2102 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00002103 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
2104 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00002105}
2106
bsalomon@google.com27847de2011-02-22 20:59:41 +00002107////////////////////////////////////////////////////////////////////////////////
2108
bsalomon@google.com27847de2011-02-22 20:59:41 +00002109void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002110 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002111 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002112 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002113}
2114
2115GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002116 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002117}
2118
2119const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002120 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002121}
2122
2123const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002124 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002125}
2126
2127void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002128 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002129}
2130
2131void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002132 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002133}
2134
2135static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2136 intptr_t mask = 1 << shift;
2137 if (pred) {
2138 bits |= mask;
2139 } else {
2140 bits &= ~mask;
2141 }
2142 return bits;
2143}
2144
2145void GrContext::resetStats() {
2146 fGpu->resetStats();
2147}
2148
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002149const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002150 return fGpu->getStats();
2151}
2152
2153void GrContext::printStats() const {
2154 fGpu->printStats();
2155}
2156
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002157GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002158 fGpu = gpu;
2159 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002160 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002161
bsalomon@google.com30085192011-08-19 15:42:31 +00002162 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002163
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002164 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2165 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002166 fFontCache = new GrFontCache(fGpu);
2167
2168 fLastDrawCategory = kUnbuffered_DrawCategory;
2169
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002170 fDrawBuffer = NULL;
2171 fDrawBufferVBAllocPool = NULL;
2172 fDrawBufferIBAllocPool = NULL;
2173
bsalomon@google.com205d4602011-04-25 12:43:45 +00002174 fAAFillRectIndexBuffer = NULL;
2175 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002176
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002177 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2178 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002179 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2180 }
2181 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002182
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002183 this->setupDrawBuffer();
2184}
2185
2186void GrContext::setupDrawBuffer() {
2187
2188 GrAssert(NULL == fDrawBuffer);
2189 GrAssert(NULL == fDrawBufferVBAllocPool);
2190 GrAssert(NULL == fDrawBufferIBAllocPool);
2191
bsalomon@google.com27847de2011-02-22 20:59:41 +00002192#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002193 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002194 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002195 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2196 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002197 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002198 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002199 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002200 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2201
bsalomon@google.com471d4712011-08-23 15:45:25 +00002202 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2203 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002204 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002205#endif
2206
2207#if BATCH_RECT_TO_RECT
2208 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2209#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002210}
2211
bsalomon@google.com27847de2011-02-22 20:59:41 +00002212GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2213 GrDrawTarget* target;
2214#if DEFER_TEXT_RENDERING
2215 target = prepareToDraw(paint, kText_DrawCategory);
2216#else
2217 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2218#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002219 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002220 return target;
2221}
2222
2223const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2224 return fGpu->getQuadIndexBuffer();
2225}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002226
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002227void GrContext::convolveInX(GrTexture* texture,
2228 const SkRect& rect,
2229 const float* kernel,
2230 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002231 ASSERT_OWNED_RESOURCE(texture);
2232
bsalomon@google.com99621082011-11-15 16:47:16 +00002233 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002234 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2235}
2236
2237void GrContext::convolveInY(GrTexture* texture,
2238 const SkRect& rect,
2239 const float* kernel,
2240 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002241 ASSERT_OWNED_RESOURCE(texture);
2242
bsalomon@google.com99621082011-11-15 16:47:16 +00002243 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002244 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2245}
2246
2247void GrContext::convolve(GrTexture* texture,
2248 const SkRect& rect,
2249 float imageIncrement[2],
2250 const float* kernel,
2251 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002252 ASSERT_OWNED_RESOURCE(texture);
2253
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002254 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002255 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002256 GrMatrix sampleM;
2257 sampleM.setIDiv(texture->width(), texture->height());
2258 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2259 GrSamplerState::kConvolution_Filter,
2260 sampleM);
2261 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2262 kernel,
2263 imageIncrement);
2264
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002265 drawState->setViewMatrix(GrMatrix::I());
2266 drawState->setTexture(0, texture);
2267 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002268 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002269 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2270}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002271
2272///////////////////////////////////////////////////////////////////////////////