blob: 213731935d435786422b921653513c2d2c2abbbd [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.com8f9cbd62011-12-09 15:55:34 +0000772 GrDrawState* drawState = target->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000773 GrMatrix vm = drawState->getViewMatrix();
774 drawState->reset();
775 *drawState->viewMatrix() = vm;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000776 drawState->setRenderTarget(offRT);
bsalomon@google.com46f7afb2012-01-18 19:51:55 +0000777
bsalomon@google.com289533a2011-10-27 12:34:25 +0000778#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com337af172012-01-11 16:00:42 +0000779 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000780#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000781
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000782 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000783 int left = boundRect.fLeft + tileX * record->fTileSizeX;
784 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000785 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000786 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000787 GrMatrix scaleM;
788 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000789 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000790
bsalomon@google.com91958362011-06-13 17:58:13 +0000791 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000792 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000793 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000794 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000795 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
796 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000797 target->setClip(GrClip(clear));
bsalomon@google.com46f7afb2012-01-18 19:51:55 +0000798 drawState->enableState(GrDrawState::kClip_StateBit);
799
bsalomon@google.com91958362011-06-13 17:58:13 +0000800#if 0
801 // visualize tile boundaries by setting edges of offscreen to white
802 // and interior to tranparent. black.
803 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000804
bsalomon@google.com91958362011-06-13 17:58:13 +0000805 static const int gOffset = 2;
806 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
807 record->fScale * w - gOffset,
808 record->fScale * h - gOffset);
809 target->clear(&clear2, 0x0);
810#else
811 target->clear(&clear, 0x0);
812#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000813}
814
bsalomon@google.com91958362011-06-13 17:58:13 +0000815void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000816 const GrPaint& paint,
817 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000818 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000819 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000820 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com46579e02012-01-11 18:51:15 +0000821 GrAssert(NULL != record->fOffscreen.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000822 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000823 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000824 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
825 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000826 tileRect.fRight = (tileX == record->fTileCountX-1) ?
827 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000828 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000829 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
830 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000831 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000832
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000833 GrSamplerState::Filter filter;
834 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
835 filter = GrSamplerState::k4x4Downsample_Filter;
836 } else {
837 filter = GrSamplerState::kBilinear_Filter;
838 }
839
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000840 GrTexture* src = record->fOffscreen.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000841 int scale;
842
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000843 enum {
844 kOffscreenStage = GrPaint::kTotalStages,
845 };
846
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000847 GrDrawState* drawState = target->drawState();
848
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000849 if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000850 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000851 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000852 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000853 } else {
854 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
855 record->fDownsample);
856 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000857 }
858
bsalomon@google.com91958362011-06-13 17:58:13 +0000859 // setup for draw back to main RT, we use the original
860 // draw state setup by the caller plus an additional coverage
861 // stage to handle the AA resolve. Also, we use an identity
862 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000863 int stageMask = paint.getActiveStageMask();
864
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000865 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000866 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000867
868 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000869 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000870 if (drawState->getViewInverse(&invVM)) {
871 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 }
873 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000874 // This is important when tiling, otherwise second tile's
875 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000876 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000877
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000878 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000879 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
880 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000881 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
882 scale * GR_Scalar1 / src->height());
883 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
884 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000885
reed@google.com20efde72011-05-09 17:00:02 +0000886 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000887 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000888 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000889 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000890}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000891
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000892void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
893 GrPathRenderer* pr,
894 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000895 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000896}
897
898////////////////////////////////////////////////////////////////////////////////
899
bsalomon@google.com27847de2011-02-22 20:59:41 +0000900/* create a triangle strip that strokes the specified triangle. There are 8
901 unique vertices, but we repreat the last 2 to close up. Alternatively we
902 could use an indices array, and then only send 8 verts, but not sure that
903 would be faster.
904 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000905static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000906 GrScalar width) {
907 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000909
910 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
911 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
912 verts[2].set(rect.fRight - rad, rect.fTop + rad);
913 verts[3].set(rect.fRight + rad, rect.fTop - rad);
914 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
915 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
916 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
917 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
918 verts[8] = verts[0];
919 verts[9] = verts[1];
920}
921
bsalomon@google.com205d4602011-04-25 12:43:45 +0000922static void setInsetFan(GrPoint* pts, size_t stride,
923 const GrRect& r, GrScalar dx, GrScalar dy) {
924 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
925}
926
927static const uint16_t gFillAARectIdx[] = {
928 0, 1, 5, 5, 4, 0,
929 1, 2, 6, 6, 5, 1,
930 2, 3, 7, 7, 6, 2,
931 3, 0, 4, 4, 7, 3,
932 4, 5, 6, 6, 7, 4,
933};
934
935int GrContext::aaFillRectIndexCount() const {
936 return GR_ARRAY_COUNT(gFillAARectIdx);
937}
938
939GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
940 if (NULL == fAAFillRectIndexBuffer) {
941 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
942 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000943 if (NULL != fAAFillRectIndexBuffer) {
944 #if GR_DEBUG
945 bool updated =
946 #endif
947 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
948 sizeof(gFillAARectIdx));
949 GR_DEBUGASSERT(updated);
950 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000951 }
952 return fAAFillRectIndexBuffer;
953}
954
955static const uint16_t gStrokeAARectIdx[] = {
956 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
957 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
958 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
959 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
960
961 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
962 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
963 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
964 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
965
966 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
967 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
968 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
969 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
970};
971
972int GrContext::aaStrokeRectIndexCount() const {
973 return GR_ARRAY_COUNT(gStrokeAARectIdx);
974}
975
976GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
977 if (NULL == fAAStrokeRectIndexBuffer) {
978 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
979 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000980 if (NULL != fAAStrokeRectIndexBuffer) {
981 #if GR_DEBUG
982 bool updated =
983 #endif
984 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
985 sizeof(gStrokeAARectIdx));
986 GR_DEBUGASSERT(updated);
987 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000988 }
989 return fAAStrokeRectIndexBuffer;
990}
991
bsalomon@google.coma3108262011-10-10 14:08:47 +0000992static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
993 bool useCoverage) {
994 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000995 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000996 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000997 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
998 }
999 }
1000 if (useCoverage) {
1001 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1002 } else {
1003 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1004 }
1005 return layout;
1006}
1007
bsalomon@google.com205d4602011-04-25 12:43:45 +00001008void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001009 const GrRect& devRect,
1010 bool useVertexCoverage) {
1011 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001012
1013 size_t vsize = GrDrawTarget::VertexSize(layout);
1014
1015 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001016 if (!geo.succeeded()) {
1017 GrPrintf("Failed to get space for vertices!\n");
1018 return;
1019 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001020 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1021 if (NULL == indexBuffer) {
1022 GrPrintf("Failed to create index buffer!\n");
1023 return;
1024 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001025
1026 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1027
1028 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1029 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1030
1031 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1032 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1033
1034 verts += sizeof(GrPoint);
1035 for (int i = 0; i < 4; ++i) {
1036 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1037 }
1038
bsalomon@google.coma3108262011-10-10 14:08:47 +00001039 GrColor innerColor;
1040 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001041 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001042 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001043 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001044 }
1045
bsalomon@google.com205d4602011-04-25 12:43:45 +00001046 verts += 4 * vsize;
1047 for (int i = 0; i < 4; ++i) {
1048 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1049 }
1050
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001051 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001052
1053 target->drawIndexed(kTriangles_PrimitiveType, 0,
1054 0, 8, this->aaFillRectIndexCount());
1055}
1056
bsalomon@google.coma3108262011-10-10 14:08:47 +00001057void GrContext::strokeAARect(GrDrawTarget* target,
1058 const GrRect& devRect,
1059 const GrVec& devStrokeSize,
1060 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001061 const GrScalar& dx = devStrokeSize.fX;
1062 const GrScalar& dy = devStrokeSize.fY;
1063 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1064 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1065
bsalomon@google.com205d4602011-04-25 12:43:45 +00001066 GrScalar spare;
1067 {
1068 GrScalar w = devRect.width() - dx;
1069 GrScalar h = devRect.height() - dy;
1070 spare = GrMin(w, h);
1071 }
1072
1073 if (spare <= 0) {
1074 GrRect r(devRect);
1075 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001076 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001077 return;
1078 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001079 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001080 size_t vsize = GrDrawTarget::VertexSize(layout);
1081
1082 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001083 if (!geo.succeeded()) {
1084 GrPrintf("Failed to get space for vertices!\n");
1085 return;
1086 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001087 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1088 if (NULL == indexBuffer) {
1089 GrPrintf("Failed to create index buffer!\n");
1090 return;
1091 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001092
1093 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1094
1095 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1096 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1097 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1098 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1099
1100 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1101 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1102 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1103 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1104
1105 verts += sizeof(GrPoint);
1106 for (int i = 0; i < 4; ++i) {
1107 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1108 }
1109
bsalomon@google.coma3108262011-10-10 14:08:47 +00001110 GrColor innerColor;
1111 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001112 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001113 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001114 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001115 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001116 verts += 4 * vsize;
1117 for (int i = 0; i < 8; ++i) {
1118 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1119 }
1120
1121 verts += 8 * vsize;
1122 for (int i = 0; i < 8; ++i) {
1123 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1124 }
1125
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001126 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001127 target->drawIndexed(kTriangles_PrimitiveType,
1128 0, 0, 16, aaStrokeRectIndexCount());
1129}
1130
reed@google.com20efde72011-05-09 17:00:02 +00001131/**
1132 * Returns true if the rects edges are integer-aligned.
1133 */
1134static bool isIRect(const GrRect& r) {
1135 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1136 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1137}
1138
bsalomon@google.com205d4602011-04-25 12:43:45 +00001139static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001140 const GrRect& rect,
1141 GrScalar width,
1142 const GrMatrix* matrix,
1143 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001144 GrRect* devRect,
1145 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001146 // we use a simple coverage ramp to do aa on axis-aligned rects
1147 // we check if the rect will be axis-aligned, and the rect won't land on
1148 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001149
bsalomon@google.coma3108262011-10-10 14:08:47 +00001150 // we are keeping around the "tweak the alpha" trick because
1151 // it is our only hope for the fixed-pipe implementation.
1152 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001153 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001154 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001155 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001156 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001157#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001158 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001159#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001160 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001161 } else {
1162 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001163 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001164 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001165 const GrDrawState& drawState = target->getDrawState();
1166 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001167 return false;
1168 }
1169
bsalomon@google.com471d4712011-08-23 15:45:25 +00001170 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001171 return false;
1172 }
1173
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001174 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001175 return false;
1176 }
1177
1178 if (NULL != matrix &&
1179 !matrix->preservesAxisAlignment()) {
1180 return false;
1181 }
1182
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001183 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001184 if (NULL != matrix) {
1185 combinedMatrix->preConcat(*matrix);
1186 GrAssert(combinedMatrix->preservesAxisAlignment());
1187 }
1188
1189 combinedMatrix->mapRect(devRect, rect);
1190 devRect->sort();
1191
1192 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001193 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001194 } else {
1195 return true;
1196 }
1197}
1198
bsalomon@google.com27847de2011-02-22 20:59:41 +00001199void GrContext::drawRect(const GrPaint& paint,
1200 const GrRect& rect,
1201 GrScalar width,
1202 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001203 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001204
1205 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001206 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001207
bsalomon@google.com205d4602011-04-25 12:43:45 +00001208 GrRect devRect = rect;
1209 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001210 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001211 bool needAA = paint.fAntiAlias &&
1212 !this->getRenderTarget()->isMultisampled();
1213 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1214 &combinedMatrix, &devRect,
1215 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001216
1217 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001218 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001219 if (width >= 0) {
1220 GrVec strokeSize;;
1221 if (width > 0) {
1222 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001223 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001224 strokeSize.setAbs(strokeSize);
1225 } else {
1226 strokeSize.set(GR_Scalar1, GR_Scalar1);
1227 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001228 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001229 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001230 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001231 }
1232 return;
1233 }
1234
bsalomon@google.com27847de2011-02-22 20:59:41 +00001235 if (width >= 0) {
1236 // TODO: consider making static vertex buffers for these cases.
1237 // Hairline could be done by just adding closing vertex to
1238 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001239 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1240
bsalomon@google.com27847de2011-02-22 20:59:41 +00001241 static const int worstCaseVertCount = 10;
1242 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1243
1244 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001245 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001246 return;
1247 }
1248
1249 GrPrimitiveType primType;
1250 int vertCount;
1251 GrPoint* vertex = geo.positions();
1252
1253 if (width > 0) {
1254 vertCount = 10;
1255 primType = kTriangleStrip_PrimitiveType;
1256 setStrokeRectStrip(vertex, rect, width);
1257 } else {
1258 // hairline
1259 vertCount = 5;
1260 primType = kLineStrip_PrimitiveType;
1261 vertex[0].set(rect.fLeft, rect.fTop);
1262 vertex[1].set(rect.fRight, rect.fTop);
1263 vertex[2].set(rect.fRight, rect.fBottom);
1264 vertex[3].set(rect.fLeft, rect.fBottom);
1265 vertex[4].set(rect.fLeft, rect.fTop);
1266 }
1267
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001268 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001270 GrDrawState* drawState = target->drawState();
1271 avmr.set(drawState);
1272 drawState->preConcatViewMatrix(*matrix);
1273 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001274 }
1275
1276 target->drawNonIndexed(primType, 0, vertCount);
1277 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001278#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001279 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001280 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1281 if (NULL == sqVB) {
1282 GrPrintf("Failed to create static rect vb.\n");
1283 return;
1284 }
1285 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001286 GrDrawState* drawState = target->drawState();
1287 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001288 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001289 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001290 0, rect.height(), rect.fTop,
1291 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292
1293 if (NULL != matrix) {
1294 m.postConcat(*matrix);
1295 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001296 drawState->preConcatViewMatrix(m);
1297 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001298
bsalomon@google.com27847de2011-02-22 20:59:41 +00001299 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001300#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001301 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001302#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001303 }
1304}
1305
1306void GrContext::drawRectToRect(const GrPaint& paint,
1307 const GrRect& dstRect,
1308 const GrRect& srcRect,
1309 const GrMatrix* dstMatrix,
1310 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001311 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001312
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001313 // srcRect refers to paint's first texture
1314 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001315 drawRect(paint, dstRect, -1, dstMatrix);
1316 return;
1317 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001318
bsalomon@google.com27847de2011-02-22 20:59:41 +00001319 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1320
1321#if GR_STATIC_RECT_VB
1322 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001323 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001324 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001325 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326
1327 GrMatrix m;
1328
1329 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1330 0, dstRect.height(), dstRect.fTop,
1331 0, 0, GrMatrix::I()[8]);
1332 if (NULL != dstMatrix) {
1333 m.postConcat(*dstMatrix);
1334 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001335 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001336
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001337 // srcRect refers to first stage
1338 int otherStageMask = paint.getActiveStageMask() &
1339 (~(1 << GrPaint::kFirstTextureStage));
1340 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001341 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001342 }
1343
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1345 0, srcRect.height(), srcRect.fTop,
1346 0, 0, GrMatrix::I()[8]);
1347 if (NULL != srcMatrix) {
1348 m.postConcat(*srcMatrix);
1349 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001350 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001351
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001352 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1353 if (NULL == sqVB) {
1354 GrPrintf("Failed to create static rect vb.\n");
1355 return;
1356 }
1357 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001358 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1359#else
1360
1361 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001362#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001363 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001364#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001365 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1366#endif
1367
tomhudson@google.com93813632011-10-27 20:21:16 +00001368 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1369 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001370 srcRects[0] = &srcRect;
1371 srcMatrices[0] = srcMatrix;
1372
1373 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1374#endif
1375}
1376
1377void GrContext::drawVertices(const GrPaint& paint,
1378 GrPrimitiveType primitiveType,
1379 int vertexCount,
1380 const GrPoint positions[],
1381 const GrPoint texCoords[],
1382 const GrColor colors[],
1383 const uint16_t indices[],
1384 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001385 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001386
1387 GrDrawTarget::AutoReleaseGeometry geo;
1388
1389 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1390
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001391 bool hasTexCoords[GrPaint::kTotalStages] = {
1392 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1393 0 // remaining stages use positions
1394 };
1395
1396 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397
1398 if (NULL != colors) {
1399 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001400 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001401 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001402
1403 if (sizeof(GrPoint) != vertexSize) {
1404 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001405 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001406 return;
1407 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001408 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001409 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001410 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1411 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001412 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001413 NULL,
1414 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 void* curVertex = geo.vertices();
1416
1417 for (int i = 0; i < vertexCount; ++i) {
1418 *((GrPoint*)curVertex) = positions[i];
1419
1420 if (texOffsets[0] > 0) {
1421 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1422 }
1423 if (colorOffset > 0) {
1424 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1425 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001426 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001427 }
1428 } else {
1429 target->setVertexSourceToArray(layout, positions, vertexCount);
1430 }
1431
bsalomon@google.com91958362011-06-13 17:58:13 +00001432 // we don't currently apply offscreen AA to this path. Need improved
1433 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001434
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001435 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001436 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001437 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001438 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001439 target->drawNonIndexed(primitiveType, 0, vertexCount);
1440 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441}
1442
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001443///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001444#include "SkDraw.h"
1445#include "SkRasterClip.h"
1446
1447namespace {
1448
1449SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1450 switch (fill) {
1451 case kWinding_PathFill:
1452 return SkPath::kWinding_FillType;
1453 case kEvenOdd_PathFill:
1454 return SkPath::kEvenOdd_FillType;
1455 case kInverseWinding_PathFill:
1456 return SkPath::kInverseWinding_FillType;
1457 case kInverseEvenOdd_PathFill:
1458 return SkPath::kInverseEvenOdd_FillType;
1459 default:
1460 GrCrash("Unexpected fill.");
1461 return SkPath::kWinding_FillType;
1462 }
1463}
1464
1465// gets device coord bounds of path (not considering the fill) and clip. The
1466// path bounds will be a subset of the clip bounds. returns false if path bounds
1467// would be empty.
1468bool get_path_and_clip_bounds(const GrDrawTarget* target,
1469 const GrPath& path,
1470 const GrVec* translate,
1471 GrIRect* pathBounds,
1472 GrIRect* clipBounds) {
1473 // compute bounds as intersection of rt size, clip, and path
1474 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1475 if (NULL == rt) {
1476 return false;
1477 }
1478 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1479 const GrClip& clip = target->getClip();
1480 if (clip.hasConservativeBounds()) {
1481 clip.getConservativeBounds().roundOut(clipBounds);
1482 if (!pathBounds->intersect(*clipBounds)) {
1483 return false;
1484 }
1485 } else {
1486 // pathBounds is currently the rt extent, set clip bounds to that rect.
1487 *clipBounds = *pathBounds;
1488 }
1489 GrRect pathSBounds = path.getBounds();
1490 if (!pathSBounds.isEmpty()) {
1491 if (NULL != translate) {
1492 pathSBounds.offset(*translate);
1493 }
1494 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1495 pathSBounds);
1496 GrIRect pathIBounds;
1497 pathSBounds.roundOut(&pathIBounds);
1498 if (!pathBounds->intersect(pathIBounds)) {
1499 return false;
1500 }
1501 } else {
1502 return false;
1503 }
1504 return true;
1505}
1506
1507/**
1508 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1509 * scratch texture.
1510 */
1511
1512bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1513 const GrIRect& pathDevBounds,
1514 GrPathFill fill,
1515 GrContext* context,
1516 const GrPoint* translate,
1517 GrAutoScratchTexture* tex) {
1518 SkPaint paint;
1519 SkPath tmpPath;
1520 const SkPath* pathToDraw = &clientPath;
1521 if (kHairLine_PathFill == fill) {
1522 paint.setStyle(SkPaint::kStroke_Style);
1523 paint.setStrokeWidth(SK_Scalar1);
1524 } else {
1525 paint.setStyle(SkPaint::kFill_Style);
1526 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1527 if (skfill != pathToDraw->getFillType()) {
1528 tmpPath = *pathToDraw;
1529 tmpPath.setFillType(skfill);
1530 pathToDraw = &tmpPath;
1531 }
1532 }
1533 paint.setAntiAlias(true);
1534 paint.setColor(SK_ColorWHITE);
1535
1536 GrMatrix matrix = context->getMatrix();
1537 if (NULL != translate) {
1538 matrix.postTranslate(translate->fX, translate->fY);
1539 }
1540
1541 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1542 -pathDevBounds.fTop * SK_Scalar1);
1543 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1544 pathDevBounds.height());
1545
1546 SkBitmap bm;
1547 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1548 if (!bm.allocPixels()) {
1549 return false;
1550 }
1551 sk_bzero(bm.getPixels(), bm.getSafeSize());
1552
1553 SkDraw draw;
1554 sk_bzero(&draw, sizeof(draw));
1555 SkRasterClip rc(bounds);
1556 draw.fRC = &rc;
1557 draw.fClip = &rc.bwRgn();
1558 draw.fMatrix = &matrix;
1559 draw.fBitmap = &bm;
1560 draw.drawPath(*pathToDraw, paint);
1561
1562 const GrTextureDesc desc = {
1563 kNone_GrTextureFlags,
1564 kNone_GrAALevel,
1565 bounds.fRight,
1566 bounds.fBottom,
1567 kAlpha_8_GrPixelConfig
1568 };
1569
1570 tex->set(context, desc);
1571 GrTexture* texture = tex->texture();
1572
1573 if (NULL == texture) {
1574 return false;
1575 }
1576 SkAutoLockPixels alp(bm);
1577 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1578 bm.getPixels(), bm.rowBytes());
1579 return true;
1580}
1581
1582void draw_around_inv_path(GrDrawTarget* target,
1583 GrDrawState::StageMask stageMask,
1584 const GrIRect& clipBounds,
1585 const GrIRect& pathBounds) {
1586 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1587 GrRect rect;
1588 if (clipBounds.fTop < pathBounds.fTop) {
1589 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1590 clipBounds.fRight, pathBounds.fTop);
1591 target->drawSimpleRect(rect, NULL, stageMask);
1592 }
1593 if (clipBounds.fLeft < pathBounds.fLeft) {
1594 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1595 pathBounds.fLeft, pathBounds.fBottom);
1596 target->drawSimpleRect(rect, NULL, stageMask);
1597 }
1598 if (clipBounds.fRight > pathBounds.fRight) {
1599 rect.iset(pathBounds.fRight, pathBounds.fTop,
1600 clipBounds.fRight, pathBounds.fBottom);
1601 target->drawSimpleRect(rect, NULL, stageMask);
1602 }
1603 if (clipBounds.fBottom > pathBounds.fBottom) {
1604 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1605 clipBounds.fRight, clipBounds.fBottom);
1606 target->drawSimpleRect(rect, NULL, stageMask);
1607 }
1608}
1609
1610}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001611
reed@google.com07f3ee12011-05-16 17:21:57 +00001612void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1613 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001615 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001616 if (GrIsFillInverted(fill)) {
1617 this->drawPaint(paint);
1618 }
1619 return;
1620 }
1621
bsalomon@google.com27847de2011-02-22 20:59:41 +00001622 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001623 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001624
bsalomon@google.com289533a2011-10-27 12:34:25 +00001625 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1626
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001627 // An Assumption here is that path renderer would use some form of tweaking
1628 // the src color (either the input alpha or in the frag shader) to implement
1629 // aa. If we have some future driver-mojo path AA that can do the right
1630 // thing WRT to the blend then we'll need some query on the PR.
1631 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001632#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001633 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001634#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001635 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001636 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001637
1638 bool doOSAA = false;
1639 GrPathRenderer* pr = NULL;
1640 if (prAA) {
1641 pr = this->getPathRenderer(path, fill, true);
1642 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001643 GrAutoScratchTexture ast;
1644 GrIRect pathBounds, clipBounds;
1645 if (!get_path_and_clip_bounds(target, path, translate,
1646 &pathBounds, &clipBounds)) {
1647 return;
1648 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001649 prAA = false;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001650 if (this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
1651 pr = this->getPathRenderer(path, fill, false);
1652 doOSAA = true;
1653 }
1654 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1655 fill, this,
1656 translate, &ast)) {
1657 GrTexture* texture = ast.texture();
1658 GrAssert(NULL != texture);
1659 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1660 enum {
1661 kPathMaskStage = GrPaint::kTotalStages,
1662 };
1663 target->drawState()->setTexture(kPathMaskStage, texture);
1664 target->drawState()->sampler(kPathMaskStage)->reset();
1665 GrScalar w = GrIntToScalar(pathBounds.width());
1666 GrScalar h = GrIntToScalar(pathBounds.height());
1667 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1668 h / texture->height());
1669 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1670 srcRects[kPathMaskStage] = &maskRect;
1671 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001672 GrRect dstRect = GrRect::MakeLTRB(
1673 SK_Scalar1* pathBounds.fLeft,
1674 SK_Scalar1* pathBounds.fTop,
1675 SK_Scalar1* pathBounds.fRight,
1676 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001677 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1678 target->drawState()->setTexture(kPathMaskStage, NULL);
1679 if (GrIsFillInverted(fill)) {
1680 draw_around_inv_path(target, stageMask,
1681 clipBounds, pathBounds);
1682 }
1683 return;
1684 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001685 }
1686 } else {
1687 pr = this->getPathRenderer(path, fill, false);
1688 }
1689
bsalomon@google.com30085192011-08-19 15:42:31 +00001690 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001691#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001692 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001693#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001694 return;
1695 }
1696
bsalomon@google.com289533a2011-10-27 12:34:25 +00001697 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001698
bsalomon@google.com289533a2011-10-27 12:34:25 +00001699 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001700 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001701 GrIRect pathBounds;
1702 GrIRect clipBounds;
1703 if (!get_path_and_clip_bounds(target, path, translate,
1704 &pathBounds, &clipBounds)) {
1705 return;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001706 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001707 OffscreenRecord record;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001708 if (this->prepareForOffscreenAA(target, needsStencil, pathBounds,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001709 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001710 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1711 for (int ty = 0; ty < record.fTileCountY; ++ty) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001712 this->setupOffscreenAAPass1(target, pathBounds,
1713 tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001714 pr->drawPath(0);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001715 this->doOffscreenAAPass2(target, paint, pathBounds,
1716 tx, ty, &record);
bsalomon@google.com91958362011-06-13 17:58:13 +00001717 }
1718 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001719 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001720 if (GrIsFillInverted(fill)) {
1721 draw_around_inv_path(target, stageMask, clipBounds, pathBounds);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001722 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001723 return;
1724 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001725 }
1726 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001727}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001728
bsalomon@google.com27847de2011-02-22 20:59:41 +00001729////////////////////////////////////////////////////////////////////////////////
1730
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001731void GrContext::flush(int flagsBitfield) {
1732 if (kDiscard_FlushBit & flagsBitfield) {
1733 fDrawBuffer->reset();
1734 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001735 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001736 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001737 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001738 fGpu->forceRenderTargetFlush();
1739 }
1740}
1741
1742void GrContext::flushText() {
1743 if (kText_DrawCategory == fLastDrawCategory) {
1744 flushDrawBuffer();
1745 }
1746}
1747
1748void GrContext::flushDrawBuffer() {
1749#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001750 if (fDrawBuffer) {
1751 fDrawBuffer->playback(fGpu);
1752 fDrawBuffer->reset();
1753 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001754#endif
1755}
1756
bsalomon@google.com6f379512011-11-16 20:36:03 +00001757void GrContext::internalWriteTexturePixels(GrTexture* texture,
1758 int left, int top,
1759 int width, int height,
1760 GrPixelConfig config,
1761 const void* buffer,
1762 size_t rowBytes,
1763 uint32_t flags) {
1764 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001765 ASSERT_OWNED_RESOURCE(texture);
1766
bsalomon@google.com6f379512011-11-16 20:36:03 +00001767 if (!(kDontFlush_PixelOpsFlag & flags)) {
1768 this->flush();
1769 }
1770 // TODO: use scratch texture to perform conversion
1771 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1772 GrPixelConfigIsUnpremultiplied(config)) {
1773 return;
1774 }
1775
1776 fGpu->writeTexturePixels(texture, left, top, width, height,
1777 config, buffer, rowBytes);
1778}
1779
1780bool GrContext::internalReadTexturePixels(GrTexture* texture,
1781 int left, int top,
1782 int width, int height,
1783 GrPixelConfig config,
1784 void* buffer,
1785 size_t rowBytes,
1786 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001787 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001788 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001789
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001790 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001791 GrRenderTarget* target = texture->asRenderTarget();
1792 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001793 return this->internalReadRenderTargetPixels(target,
1794 left, top, width, height,
1795 config, buffer, rowBytes,
1796 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001797 } else {
1798 return false;
1799 }
1800}
1801
bsalomon@google.com6f379512011-11-16 20:36:03 +00001802bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1803 int left, int top,
1804 int width, int height,
1805 GrPixelConfig config,
1806 void* buffer,
1807 size_t rowBytes,
1808 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001809 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001810 ASSERT_OWNED_RESOURCE(target);
1811
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001812 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001813 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001814 if (NULL == target) {
1815 return false;
1816 }
1817 }
1818
1819 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1820 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1821 // not supported at this time.
1822 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1823 !GrPixelConfigIsUnpremultiplied(config)) {
1824 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001825 }
1826
bsalomon@google.com6f379512011-11-16 20:36:03 +00001827 if (!(kDontFlush_PixelOpsFlag & flags)) {
1828 this->flush();
1829 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001830
1831 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001832 bool swapRAndB = NULL != src &&
1833 fGpu->preferredReadPixelsConfig(config) ==
1834 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001835
1836 bool flipY = NULL != src &&
1837 fGpu->readPixelsWillPayForYFlip(target, left, top,
1838 width, height, config,
1839 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001840 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1841 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001842
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001843 if (NULL == src && alphaConversion) {
1844 // we should fallback to cpu conversion here. This could happen when
1845 // we were given an external render target by the client that is not
1846 // also a texture (e.g. FBO 0 in GL)
1847 return false;
1848 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001849 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001850 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001851 if (flipY || swapRAndB || alphaConversion) {
1852 GrAssert(NULL != src);
1853 if (swapRAndB) {
1854 config = GrPixelConfigSwapRAndB(config);
1855 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001856 }
1857 // Make the scratch a render target because we don't have a robust
1858 // readTexturePixels as of yet (it calls this function).
1859 const GrTextureDesc desc = {
1860 kRenderTarget_GrTextureFlagBit,
1861 kNone_GrAALevel,
1862 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001863 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001864 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001865
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001866 // When a full readback is faster than a partial we could always make
1867 // the scratch exactly match the passed rect. However, if we see many
1868 // different size rectangles we will trash our texture cache and pay the
1869 // cost of creating and destroying many textures. So, we only request
1870 // an exact match when the caller is reading an entire RT.
1871 ScratchTexMatch match = kApprox_ScratchTexMatch;
1872 if (0 == left &&
1873 0 == top &&
1874 target->width() == width &&
1875 target->height() == height &&
1876 fGpu->fullReadPixelsIsFasterThanPartial()) {
1877 match = kExact_ScratchTexMatch;
1878 }
1879 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001880 GrTexture* texture = ast.texture();
1881 if (!texture) {
1882 return false;
1883 }
1884 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001885 GrAssert(NULL != target);
1886
1887 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001888 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001889 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001890 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001891
bsalomon@google.comc4364992011-11-07 15:54:49 +00001892 GrMatrix matrix;
1893 if (flipY) {
1894 matrix.setTranslate(SK_Scalar1 * left,
1895 SK_Scalar1 * (top + height));
1896 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1897 } else {
1898 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1899 }
1900 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001901 drawState->sampler(0)->reset(matrix);
1902 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001903 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001904 GrRect rect;
1905 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1906 fGpu->drawSimpleRect(rect, NULL, 0x1);
1907 left = 0;
1908 top = 0;
1909 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001910 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001911 left, top, width, height,
1912 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001913}
1914
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001915void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1916 if (NULL == src || NULL == dst) {
1917 return;
1918 }
1919 ASSERT_OWNED_RESOURCE(src);
1920
1921 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001922 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001923 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001924 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001925 GrMatrix sampleM;
1926 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001927 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001928 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001929 SkRect rect = SkRect::MakeXYWH(0, 0,
1930 SK_Scalar1 * src->width(),
1931 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001932 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1933}
1934
bsalomon@google.com6f379512011-11-16 20:36:03 +00001935void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1936 int left, int top,
1937 int width, int height,
1938 GrPixelConfig config,
1939 const void* buffer,
1940 size_t rowBytes,
1941 uint32_t flags) {
1942 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001943 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001944
1945 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001946 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001947 if (NULL == target) {
1948 return;
1949 }
1950 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001951
1952 // TODO: when underlying api has a direct way to do this we should use it
1953 // (e.g. glDrawPixels on desktop GL).
1954
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001955 // If the RT is also a texture and we don't have to do PM/UPM conversion
1956 // then take the texture path, which we expect to be at least as fast or
1957 // faster since it doesn't use an intermediate texture as we do below.
1958
1959#if !GR_MAC_BUILD
1960 // At least some drivers on the Mac get confused when glTexImage2D is called
1961 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1962 // determine what OS versions and/or HW is affected.
1963 if (NULL != target->asTexture() &&
1964 GrPixelConfigIsUnpremultiplied(target->config()) ==
1965 GrPixelConfigIsUnpremultiplied(config)) {
1966
1967 this->internalWriteTexturePixels(target->asTexture(),
1968 left, top, width, height,
1969 config, buffer, rowBytes, flags);
1970 return;
1971 }
1972#endif
1973
1974 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1975 GrPixelConfigSwapRAndB(config);
1976 if (swapRAndB) {
1977 config = GrPixelConfigSwapRAndB(config);
1978 }
1979
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001980 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001981 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001983 GrAutoScratchTexture ast(this, desc);
1984 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001985 if (NULL == texture) {
1986 return;
1987 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001988 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1989 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001990
bsalomon@google.com27847de2011-02-22 20:59:41 +00001991 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001992 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001993 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001994
1995 GrMatrix matrix;
1996 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001997 drawState->setViewMatrix(matrix);
1998 drawState->setRenderTarget(target);
1999 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002000
bsalomon@google.com5c638652011-07-18 19:31:59 +00002001 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002002 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2003 GrSamplerState::kNearest_Filter,
2004 matrix);
2005 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002006
2007 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
2008 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002009 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00002010 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
2011 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002012 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00002013 return;
2014 }
2015 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
2016 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
2017}
2018////////////////////////////////////////////////////////////////////////////////
2019
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002020void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002021 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002022
2023 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
2024 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002025 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002026 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002027 if (paint.getTexture(i)) {
2028 *drawState->sampler(s) = paint.getTextureSampler(i);
2029 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002030 }
2031
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002032 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002033
2034 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
2035 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002036 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002037 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002038 if (paint.getMask(i)) {
2039 *drawState->sampler(s) = paint.getMaskSampler(i);
2040 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002041 }
2042
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002043 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002044
2045 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002046 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002047 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002048 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002049 }
2050 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002051 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002052 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002053 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002054 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002055 if (paint.fColorMatrixEnabled) {
2056 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
2057 } else {
2058 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
2059 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002060 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002061 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002062 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00002063
2064 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
2065 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
2066 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002067}
2068
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002069GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002070 DrawCategory category) {
2071 if (category != fLastDrawCategory) {
2072 flushDrawBuffer();
2073 fLastDrawCategory = category;
2074 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002075 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002076 GrDrawTarget* target = fGpu;
2077 switch (category) {
2078 case kText_DrawCategory:
2079#if DEFER_TEXT_RENDERING
2080 target = fDrawBuffer;
2081 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2082#else
2083 target = fGpu;
2084#endif
2085 break;
2086 case kUnbuffered_DrawCategory:
2087 target = fGpu;
2088 break;
2089 case kBuffered_DrawCategory:
2090 target = fDrawBuffer;
2091 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2092 break;
2093 }
2094 return target;
2095}
2096
bsalomon@google.com289533a2011-10-27 12:34:25 +00002097GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
2098 GrPathFill fill,
2099 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00002100 if (NULL == fPathRendererChain) {
2101 fPathRendererChain =
2102 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
2103 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00002104 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
2105 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00002106}
2107
bsalomon@google.com27847de2011-02-22 20:59:41 +00002108////////////////////////////////////////////////////////////////////////////////
2109
bsalomon@google.com27847de2011-02-22 20:59:41 +00002110void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002111 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002112 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002113 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002114}
2115
2116GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002117 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002118}
2119
2120const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002121 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002122}
2123
2124const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002125 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002126}
2127
2128void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002129 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002130}
2131
2132void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002133 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002134}
2135
2136static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2137 intptr_t mask = 1 << shift;
2138 if (pred) {
2139 bits |= mask;
2140 } else {
2141 bits &= ~mask;
2142 }
2143 return bits;
2144}
2145
2146void GrContext::resetStats() {
2147 fGpu->resetStats();
2148}
2149
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002150const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002151 return fGpu->getStats();
2152}
2153
2154void GrContext::printStats() const {
2155 fGpu->printStats();
2156}
2157
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002158GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002159 fGpu = gpu;
2160 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002161 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002162
bsalomon@google.com30085192011-08-19 15:42:31 +00002163 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002164
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002165 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2166 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002167 fFontCache = new GrFontCache(fGpu);
2168
2169 fLastDrawCategory = kUnbuffered_DrawCategory;
2170
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002171 fDrawBuffer = NULL;
2172 fDrawBufferVBAllocPool = NULL;
2173 fDrawBufferIBAllocPool = NULL;
2174
bsalomon@google.com205d4602011-04-25 12:43:45 +00002175 fAAFillRectIndexBuffer = NULL;
2176 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002177
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002178 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2179 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002180 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2181 }
2182 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002183
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002184 this->setupDrawBuffer();
2185}
2186
2187void GrContext::setupDrawBuffer() {
2188
2189 GrAssert(NULL == fDrawBuffer);
2190 GrAssert(NULL == fDrawBufferVBAllocPool);
2191 GrAssert(NULL == fDrawBufferIBAllocPool);
2192
bsalomon@google.com27847de2011-02-22 20:59:41 +00002193#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002194 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002195 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002196 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2197 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002198 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002199 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002200 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002201 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2202
bsalomon@google.com471d4712011-08-23 15:45:25 +00002203 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2204 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002205 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002206#endif
2207
2208#if BATCH_RECT_TO_RECT
2209 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2210#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002211}
2212
bsalomon@google.com27847de2011-02-22 20:59:41 +00002213GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2214 GrDrawTarget* target;
2215#if DEFER_TEXT_RENDERING
2216 target = prepareToDraw(paint, kText_DrawCategory);
2217#else
2218 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2219#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002220 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002221 return target;
2222}
2223
2224const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2225 return fGpu->getQuadIndexBuffer();
2226}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002227
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002228void GrContext::convolveInX(GrTexture* texture,
2229 const SkRect& rect,
2230 const float* kernel,
2231 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002232 ASSERT_OWNED_RESOURCE(texture);
2233
bsalomon@google.com99621082011-11-15 16:47:16 +00002234 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002235 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2236}
2237
2238void GrContext::convolveInY(GrTexture* texture,
2239 const SkRect& rect,
2240 const float* kernel,
2241 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002242 ASSERT_OWNED_RESOURCE(texture);
2243
bsalomon@google.com99621082011-11-15 16:47:16 +00002244 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002245 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2246}
2247
2248void GrContext::convolve(GrTexture* texture,
2249 const SkRect& rect,
2250 float imageIncrement[2],
2251 const float* kernel,
2252 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002253 ASSERT_OWNED_RESOURCE(texture);
2254
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002255 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002256 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002257 GrMatrix sampleM;
2258 sampleM.setIDiv(texture->width(), texture->height());
2259 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2260 GrSamplerState::kConvolution_Filter,
2261 sampleM);
2262 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2263 kernel,
2264 imageIncrement);
2265
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002266 drawState->setViewMatrix(GrMatrix::I());
2267 drawState->setTexture(0, texture);
2268 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002269 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002270 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2271}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002272
2273///////////////////////////////////////////////////////////////////////////////