blob: 2132ed6ea7b0f46b8b6690c5eb61310e16be081c [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 +0000544///////////////////////////////////////////////////////////////////////////////
545
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000546bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000547 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000548 const GrDrawTarget::Caps& caps = fGpu->getCaps();
549 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000550 return false;
551 }
552
bsalomon@google.com27847de2011-02-22 20:59:41 +0000553 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
554
555 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000556 bool tiled = NULL != sampler &&
557 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
558 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000559 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000560 return false;
561 }
562 }
563 return true;
564}
565
566////////////////////////////////////////////////////////////////////////////////
567
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000568const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
569
bsalomon@google.com27847de2011-02-22 20:59:41 +0000570void GrContext::setClip(const GrClip& clip) {
571 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000572 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000573}
574
575void GrContext::setClip(const GrIRect& rect) {
576 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000577 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000578 fGpu->setClip(clip);
579}
580
581////////////////////////////////////////////////////////////////////////////////
582
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000583void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000584 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000585 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000586}
587
588void GrContext::drawPaint(const GrPaint& paint) {
589 // set rect to be big enough to fill the space, but not super-huge, so we
590 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000591 GrRect r;
592 r.setLTRB(0, 0,
593 GrIntToScalar(getRenderTarget()->width()),
594 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000595 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000596 SkTLazy<GrPaint> tmpPaint;
597 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000598 GrDrawState* drawState = fGpu->drawState();
599 GrAutoMatrix am;
600
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000601 // We attempt to map r by the inverse matrix and draw that. mapRect will
602 // map the four corners and bound them with a new rect. This will not
603 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000604 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000605 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000606 GrPrintf("Could not invert matrix");
607 return;
608 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000609 inverse.mapRect(&r);
610 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000611 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000612 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000613 GrPrintf("Could not invert matrix");
614 return;
615 }
616 tmpPaint.set(paint);
617 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
618 p = tmpPaint.get();
619 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000620 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000621 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000622 // by definition this fills the entire clip, no need for AA
623 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000624 if (!tmpPaint.isValid()) {
625 tmpPaint.set(paint);
626 p = tmpPaint.get();
627 }
628 GrAssert(p == tmpPaint.get());
629 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000630 }
631 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000632}
633
bsalomon@google.com205d4602011-04-25 12:43:45 +0000634////////////////////////////////////////////////////////////////////////////////
635
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000636namespace {
637inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
638 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
639}
640}
641
bsalomon@google.com91958362011-06-13 17:58:13 +0000642struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000643 enum Downsample {
bsalomon@google.com91958362011-06-13 17:58:13 +0000644 k4x4SinglePass_Downsample,
645 kFSAA_Downsample
646 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000647 int fTileSizeX;
648 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000649 int fTileCountX;
650 int fTileCountY;
651 int fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000652 GrAutoScratchTexture fOffscreen;
bsalomon@google.com91958362011-06-13 17:58:13 +0000653 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000654 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000655};
656
bsalomon@google.com471d4712011-08-23 15:45:25 +0000657bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000658 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000659#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000660 return false;
661#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000662 // Line primitves are always rasterized as 1 pixel wide.
663 // Super-sampling would make them too thin but MSAA would be OK.
664 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000665 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000666 return false;
667 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000668 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000669 return false;
670 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000671 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000672#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000673 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000674#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000675 return false;
676 }
677 return true;
678#endif
679}
680
bsalomon@google.com91958362011-06-13 17:58:13 +0000681bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000682 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000683 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000684 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000685 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000686
687 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000688
bsalomon@google.com46579e02012-01-11 18:51:15 +0000689 GrAssert(NULL == record->fOffscreen.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000690 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000691
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000692 int boundW = boundRect.width();
693 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000694
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000695 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000696
697 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
698 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
699
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000700 if (requireStencil) {
701 desc.fFlags = kRenderTarget_GrTextureFlagBit;
702 } else {
703 desc.fFlags = kRenderTarget_GrTextureFlagBit |
704 kNoStencil_GrTextureFlagBit;
705 }
706
bsalomon@google.comc4364992011-11-07 15:54:49 +0000707 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000708
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000709 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000710 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000711 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000712 desc.fAALevel = kMed_GrAALevel;
713 } else {
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000714 record->fDownsample = OffscreenRecord::k4x4SinglePass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000715 record->fScale = OFFSCREEN_SSAA_SCALE;
716 // both downsample paths assume this
717 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000718 desc.fAALevel = kNone_GrAALevel;
719 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000720
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000721 desc.fWidth *= record->fScale;
722 desc.fHeight *= record->fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000723 record->fOffscreen.set(this, desc);
724 if (NULL == record->fOffscreen.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000725 return false;
726 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000727 // the approximate lookup might have given us some slop space, might as well
728 // use it when computing the tiles size.
729 // these are scale values, will adjust after considering
730 // the possible second offscreen.
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000731 record->fTileSizeX = record->fOffscreen.texture()->width();
732 record->fTileSizeY = record->fOffscreen.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000733
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000734 record->fTileSizeX /= record->fScale;
735 record->fTileSizeY /= record->fScale;
736
737 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
738 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
739
tomhudson@google.com237a4612011-07-19 15:44:00 +0000740 record->fClip = target->getClip();
741
bsalomon@google.com91958362011-06-13 17:58:13 +0000742 target->saveCurrentDrawState(&record->fSavedState);
743 return true;
744}
745
746void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
747 const GrIRect& boundRect,
748 int tileX, int tileY,
749 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000750
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000751 GrRenderTarget* offRT = record->fOffscreen.texture()->asRenderTarget();
752 GrAssert(NULL != offRT);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000753
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000754 GrDrawState* drawState = target->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000755 GrMatrix vm = drawState->getViewMatrix();
756 drawState->reset();
757 *drawState->viewMatrix() = vm;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000758 drawState->setRenderTarget(offRT);
bsalomon@google.com46f7afb2012-01-18 19:51:55 +0000759
bsalomon@google.com289533a2011-10-27 12:34:25 +0000760#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com337af172012-01-11 16:00:42 +0000761 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000762#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000763
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000764 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000765 int left = boundRect.fLeft + tileX * record->fTileSizeX;
766 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000767 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000768 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000769 GrMatrix scaleM;
770 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000771 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000772
bsalomon@google.com91958362011-06-13 17:58:13 +0000773 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000774 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000775 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000776 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000777 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
778 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000779 target->setClip(GrClip(clear));
bsalomon@google.com46f7afb2012-01-18 19:51:55 +0000780 drawState->enableState(GrDrawState::kClip_StateBit);
781
bsalomon@google.com91958362011-06-13 17:58:13 +0000782#if 0
783 // visualize tile boundaries by setting edges of offscreen to white
784 // and interior to tranparent. black.
785 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000786
bsalomon@google.com91958362011-06-13 17:58:13 +0000787 static const int gOffset = 2;
788 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
789 record->fScale * w - gOffset,
790 record->fScale * h - gOffset);
791 target->clear(&clear2, 0x0);
792#else
793 target->clear(&clear, 0x0);
794#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000795}
796
bsalomon@google.com91958362011-06-13 17:58:13 +0000797void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000798 const GrPaint& paint,
799 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000800 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000801 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000802 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com46579e02012-01-11 18:51:15 +0000803 GrAssert(NULL != record->fOffscreen.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000804 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000805 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000806 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
807 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000808 tileRect.fRight = (tileX == record->fTileCountX-1) ?
809 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000811 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
812 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000813 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000814
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000815 GrSamplerState::Filter filter;
816 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
817 filter = GrSamplerState::k4x4Downsample_Filter;
818 } else {
819 filter = GrSamplerState::kBilinear_Filter;
820 }
821
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000822 GrTexture* src = record->fOffscreen.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000823 int scale;
824
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000825 enum {
826 kOffscreenStage = GrPaint::kTotalStages,
827 };
828
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000829 GrDrawState* drawState = target->drawState();
830
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000831 if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000832 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000833 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000834 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000835 } else {
836 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
837 record->fDownsample);
838 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000839 }
840
bsalomon@google.com91958362011-06-13 17:58:13 +0000841 // setup for draw back to main RT, we use the original
842 // draw state setup by the caller plus an additional coverage
843 // stage to handle the AA resolve. Also, we use an identity
844 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000845 int stageMask = paint.getActiveStageMask();
846
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000847 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000848 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000849
850 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000852 if (drawState->getViewInverse(&invVM)) {
853 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000854 }
855 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000856 // This is important when tiling, otherwise second tile's
857 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000858 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000859
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000860 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000861 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
862 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000863 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
864 scale * GR_Scalar1 / src->height());
865 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
866 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000867
reed@google.com20efde72011-05-09 17:00:02 +0000868 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000869 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000870 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000872}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000873
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000874void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
875 GrPathRenderer* pr,
876 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000877 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000878}
879
880////////////////////////////////////////////////////////////////////////////////
881
bsalomon@google.com27847de2011-02-22 20:59:41 +0000882/* create a triangle strip that strokes the specified triangle. There are 8
883 unique vertices, but we repreat the last 2 to close up. Alternatively we
884 could use an indices array, and then only send 8 verts, but not sure that
885 would be faster.
886 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000887static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000888 GrScalar width) {
889 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000890 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000891
892 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
893 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
894 verts[2].set(rect.fRight - rad, rect.fTop + rad);
895 verts[3].set(rect.fRight + rad, rect.fTop - rad);
896 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
897 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
898 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
899 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
900 verts[8] = verts[0];
901 verts[9] = verts[1];
902}
903
bsalomon@google.com205d4602011-04-25 12:43:45 +0000904static void setInsetFan(GrPoint* pts, size_t stride,
905 const GrRect& r, GrScalar dx, GrScalar dy) {
906 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
907}
908
909static const uint16_t gFillAARectIdx[] = {
910 0, 1, 5, 5, 4, 0,
911 1, 2, 6, 6, 5, 1,
912 2, 3, 7, 7, 6, 2,
913 3, 0, 4, 4, 7, 3,
914 4, 5, 6, 6, 7, 4,
915};
916
917int GrContext::aaFillRectIndexCount() const {
918 return GR_ARRAY_COUNT(gFillAARectIdx);
919}
920
921GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
922 if (NULL == fAAFillRectIndexBuffer) {
923 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
924 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000925 if (NULL != fAAFillRectIndexBuffer) {
926 #if GR_DEBUG
927 bool updated =
928 #endif
929 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
930 sizeof(gFillAARectIdx));
931 GR_DEBUGASSERT(updated);
932 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000933 }
934 return fAAFillRectIndexBuffer;
935}
936
937static const uint16_t gStrokeAARectIdx[] = {
938 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
939 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
940 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
941 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
942
943 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
944 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
945 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
946 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
947
948 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
949 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
950 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
951 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
952};
953
954int GrContext::aaStrokeRectIndexCount() const {
955 return GR_ARRAY_COUNT(gStrokeAARectIdx);
956}
957
958GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
959 if (NULL == fAAStrokeRectIndexBuffer) {
960 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
961 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000962 if (NULL != fAAStrokeRectIndexBuffer) {
963 #if GR_DEBUG
964 bool updated =
965 #endif
966 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
967 sizeof(gStrokeAARectIdx));
968 GR_DEBUGASSERT(updated);
969 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000970 }
971 return fAAStrokeRectIndexBuffer;
972}
973
bsalomon@google.coma3108262011-10-10 14:08:47 +0000974static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
975 bool useCoverage) {
976 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000977 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000978 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000979 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
980 }
981 }
982 if (useCoverage) {
983 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
984 } else {
985 layout |= GrDrawTarget::kColor_VertexLayoutBit;
986 }
987 return layout;
988}
989
bsalomon@google.com205d4602011-04-25 12:43:45 +0000990void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000991 const GrRect& devRect,
992 bool useVertexCoverage) {
993 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000994
995 size_t vsize = GrDrawTarget::VertexSize(layout);
996
997 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000998 if (!geo.succeeded()) {
999 GrPrintf("Failed to get space for vertices!\n");
1000 return;
1001 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001002 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1003 if (NULL == indexBuffer) {
1004 GrPrintf("Failed to create index buffer!\n");
1005 return;
1006 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001007
1008 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1009
1010 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1011 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1012
1013 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1014 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1015
1016 verts += sizeof(GrPoint);
1017 for (int i = 0; i < 4; ++i) {
1018 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1019 }
1020
bsalomon@google.coma3108262011-10-10 14:08:47 +00001021 GrColor innerColor;
1022 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001023 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001024 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001025 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001026 }
1027
bsalomon@google.com205d4602011-04-25 12:43:45 +00001028 verts += 4 * vsize;
1029 for (int i = 0; i < 4; ++i) {
1030 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1031 }
1032
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001033 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001034
1035 target->drawIndexed(kTriangles_PrimitiveType, 0,
1036 0, 8, this->aaFillRectIndexCount());
1037}
1038
bsalomon@google.coma3108262011-10-10 14:08:47 +00001039void GrContext::strokeAARect(GrDrawTarget* target,
1040 const GrRect& devRect,
1041 const GrVec& devStrokeSize,
1042 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001043 const GrScalar& dx = devStrokeSize.fX;
1044 const GrScalar& dy = devStrokeSize.fY;
1045 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1046 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1047
bsalomon@google.com205d4602011-04-25 12:43:45 +00001048 GrScalar spare;
1049 {
1050 GrScalar w = devRect.width() - dx;
1051 GrScalar h = devRect.height() - dy;
1052 spare = GrMin(w, h);
1053 }
1054
1055 if (spare <= 0) {
1056 GrRect r(devRect);
1057 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001059 return;
1060 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001061 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001062 size_t vsize = GrDrawTarget::VertexSize(layout);
1063
1064 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001065 if (!geo.succeeded()) {
1066 GrPrintf("Failed to get space for vertices!\n");
1067 return;
1068 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001069 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1070 if (NULL == indexBuffer) {
1071 GrPrintf("Failed to create index buffer!\n");
1072 return;
1073 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001074
1075 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1076
1077 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1078 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1079 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1080 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1081
1082 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1083 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1084 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1085 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1086
1087 verts += sizeof(GrPoint);
1088 for (int i = 0; i < 4; ++i) {
1089 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1090 }
1091
bsalomon@google.coma3108262011-10-10 14:08:47 +00001092 GrColor innerColor;
1093 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001094 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001095 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001096 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001097 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001098 verts += 4 * vsize;
1099 for (int i = 0; i < 8; ++i) {
1100 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1101 }
1102
1103 verts += 8 * vsize;
1104 for (int i = 0; i < 8; ++i) {
1105 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1106 }
1107
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001108 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001109 target->drawIndexed(kTriangles_PrimitiveType,
1110 0, 0, 16, aaStrokeRectIndexCount());
1111}
1112
reed@google.com20efde72011-05-09 17:00:02 +00001113/**
1114 * Returns true if the rects edges are integer-aligned.
1115 */
1116static bool isIRect(const GrRect& r) {
1117 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1118 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1119}
1120
bsalomon@google.com205d4602011-04-25 12:43:45 +00001121static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001122 const GrRect& rect,
1123 GrScalar width,
1124 const GrMatrix* matrix,
1125 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001126 GrRect* devRect,
1127 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001128 // we use a simple coverage ramp to do aa on axis-aligned rects
1129 // we check if the rect will be axis-aligned, and the rect won't land on
1130 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001131
bsalomon@google.coma3108262011-10-10 14:08:47 +00001132 // we are keeping around the "tweak the alpha" trick because
1133 // it is our only hope for the fixed-pipe implementation.
1134 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001135 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001136 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001137 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001138 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001139#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001140 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001141#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001142 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001143 } else {
1144 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001145 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001146 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001147 const GrDrawState& drawState = target->getDrawState();
1148 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001149 return false;
1150 }
1151
bsalomon@google.com471d4712011-08-23 15:45:25 +00001152 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001153 return false;
1154 }
1155
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001156 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001157 return false;
1158 }
1159
1160 if (NULL != matrix &&
1161 !matrix->preservesAxisAlignment()) {
1162 return false;
1163 }
1164
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001165 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001166 if (NULL != matrix) {
1167 combinedMatrix->preConcat(*matrix);
1168 GrAssert(combinedMatrix->preservesAxisAlignment());
1169 }
1170
1171 combinedMatrix->mapRect(devRect, rect);
1172 devRect->sort();
1173
1174 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001175 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001176 } else {
1177 return true;
1178 }
1179}
1180
bsalomon@google.com27847de2011-02-22 20:59:41 +00001181void GrContext::drawRect(const GrPaint& paint,
1182 const GrRect& rect,
1183 GrScalar width,
1184 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001185 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001186
1187 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001188 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001189
bsalomon@google.com205d4602011-04-25 12:43:45 +00001190 GrRect devRect = rect;
1191 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001192 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001193 bool needAA = paint.fAntiAlias &&
1194 !this->getRenderTarget()->isMultisampled();
1195 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1196 &combinedMatrix, &devRect,
1197 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001198
1199 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001200 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001201 if (width >= 0) {
1202 GrVec strokeSize;;
1203 if (width > 0) {
1204 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001205 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001206 strokeSize.setAbs(strokeSize);
1207 } else {
1208 strokeSize.set(GR_Scalar1, GR_Scalar1);
1209 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001210 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001211 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001212 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001213 }
1214 return;
1215 }
1216
bsalomon@google.com27847de2011-02-22 20:59:41 +00001217 if (width >= 0) {
1218 // TODO: consider making static vertex buffers for these cases.
1219 // Hairline could be done by just adding closing vertex to
1220 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001221 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1222
bsalomon@google.com27847de2011-02-22 20:59:41 +00001223 static const int worstCaseVertCount = 10;
1224 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1225
1226 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001227 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001228 return;
1229 }
1230
1231 GrPrimitiveType primType;
1232 int vertCount;
1233 GrPoint* vertex = geo.positions();
1234
1235 if (width > 0) {
1236 vertCount = 10;
1237 primType = kTriangleStrip_PrimitiveType;
1238 setStrokeRectStrip(vertex, rect, width);
1239 } else {
1240 // hairline
1241 vertCount = 5;
1242 primType = kLineStrip_PrimitiveType;
1243 vertex[0].set(rect.fLeft, rect.fTop);
1244 vertex[1].set(rect.fRight, rect.fTop);
1245 vertex[2].set(rect.fRight, rect.fBottom);
1246 vertex[3].set(rect.fLeft, rect.fBottom);
1247 vertex[4].set(rect.fLeft, rect.fTop);
1248 }
1249
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001250 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001251 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001252 GrDrawState* drawState = target->drawState();
1253 avmr.set(drawState);
1254 drawState->preConcatViewMatrix(*matrix);
1255 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001256 }
1257
1258 target->drawNonIndexed(primType, 0, vertCount);
1259 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001260#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001261 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001262 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1263 if (NULL == sqVB) {
1264 GrPrintf("Failed to create static rect vb.\n");
1265 return;
1266 }
1267 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001268 GrDrawState* drawState = target->drawState();
1269 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001270 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001271 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001272 0, rect.height(), rect.fTop,
1273 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001274
1275 if (NULL != matrix) {
1276 m.postConcat(*matrix);
1277 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001278 drawState->preConcatViewMatrix(m);
1279 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001280
bsalomon@google.com27847de2011-02-22 20:59:41 +00001281 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001282#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001283 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001284#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001285 }
1286}
1287
1288void GrContext::drawRectToRect(const GrPaint& paint,
1289 const GrRect& dstRect,
1290 const GrRect& srcRect,
1291 const GrMatrix* dstMatrix,
1292 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001293 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001294
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001295 // srcRect refers to paint's first texture
1296 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001297 drawRect(paint, dstRect, -1, dstMatrix);
1298 return;
1299 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001300
bsalomon@google.com27847de2011-02-22 20:59:41 +00001301 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1302
1303#if GR_STATIC_RECT_VB
1304 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001305 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001306 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001307 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001308
1309 GrMatrix m;
1310
1311 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1312 0, dstRect.height(), dstRect.fTop,
1313 0, 0, GrMatrix::I()[8]);
1314 if (NULL != dstMatrix) {
1315 m.postConcat(*dstMatrix);
1316 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001317 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001318
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001319 // srcRect refers to first stage
1320 int otherStageMask = paint.getActiveStageMask() &
1321 (~(1 << GrPaint::kFirstTextureStage));
1322 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001323 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001324 }
1325
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1327 0, srcRect.height(), srcRect.fTop,
1328 0, 0, GrMatrix::I()[8]);
1329 if (NULL != srcMatrix) {
1330 m.postConcat(*srcMatrix);
1331 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001332 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001333
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001334 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1335 if (NULL == sqVB) {
1336 GrPrintf("Failed to create static rect vb.\n");
1337 return;
1338 }
1339 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001340 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1341#else
1342
1343 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001344#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001345 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001346#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001347 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1348#endif
1349
tomhudson@google.com93813632011-10-27 20:21:16 +00001350 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1351 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001352 srcRects[0] = &srcRect;
1353 srcMatrices[0] = srcMatrix;
1354
1355 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1356#endif
1357}
1358
1359void GrContext::drawVertices(const GrPaint& paint,
1360 GrPrimitiveType primitiveType,
1361 int vertexCount,
1362 const GrPoint positions[],
1363 const GrPoint texCoords[],
1364 const GrColor colors[],
1365 const uint16_t indices[],
1366 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001367 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001368
1369 GrDrawTarget::AutoReleaseGeometry geo;
1370
1371 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1372
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001373 bool hasTexCoords[GrPaint::kTotalStages] = {
1374 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1375 0 // remaining stages use positions
1376 };
1377
1378 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379
1380 if (NULL != colors) {
1381 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001382 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001383 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001384
1385 if (sizeof(GrPoint) != vertexSize) {
1386 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001387 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001388 return;
1389 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001390 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001391 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001392 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1393 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001394 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001395 NULL,
1396 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397 void* curVertex = geo.vertices();
1398
1399 for (int i = 0; i < vertexCount; ++i) {
1400 *((GrPoint*)curVertex) = positions[i];
1401
1402 if (texOffsets[0] > 0) {
1403 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1404 }
1405 if (colorOffset > 0) {
1406 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1407 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001408 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001409 }
1410 } else {
1411 target->setVertexSourceToArray(layout, positions, vertexCount);
1412 }
1413
bsalomon@google.com91958362011-06-13 17:58:13 +00001414 // we don't currently apply offscreen AA to this path. Need improved
1415 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001416
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001417 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001418 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001419 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001421 target->drawNonIndexed(primitiveType, 0, vertexCount);
1422 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423}
1424
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001425///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001426#include "SkDraw.h"
1427#include "SkRasterClip.h"
1428
1429namespace {
1430
1431SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1432 switch (fill) {
1433 case kWinding_PathFill:
1434 return SkPath::kWinding_FillType;
1435 case kEvenOdd_PathFill:
1436 return SkPath::kEvenOdd_FillType;
1437 case kInverseWinding_PathFill:
1438 return SkPath::kInverseWinding_FillType;
1439 case kInverseEvenOdd_PathFill:
1440 return SkPath::kInverseEvenOdd_FillType;
1441 default:
1442 GrCrash("Unexpected fill.");
1443 return SkPath::kWinding_FillType;
1444 }
1445}
1446
1447// gets device coord bounds of path (not considering the fill) and clip. The
1448// path bounds will be a subset of the clip bounds. returns false if path bounds
1449// would be empty.
1450bool get_path_and_clip_bounds(const GrDrawTarget* target,
1451 const GrPath& path,
1452 const GrVec* translate,
1453 GrIRect* pathBounds,
1454 GrIRect* clipBounds) {
1455 // compute bounds as intersection of rt size, clip, and path
1456 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1457 if (NULL == rt) {
1458 return false;
1459 }
1460 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1461 const GrClip& clip = target->getClip();
1462 if (clip.hasConservativeBounds()) {
1463 clip.getConservativeBounds().roundOut(clipBounds);
1464 if (!pathBounds->intersect(*clipBounds)) {
1465 return false;
1466 }
1467 } else {
1468 // pathBounds is currently the rt extent, set clip bounds to that rect.
1469 *clipBounds = *pathBounds;
1470 }
1471 GrRect pathSBounds = path.getBounds();
1472 if (!pathSBounds.isEmpty()) {
1473 if (NULL != translate) {
1474 pathSBounds.offset(*translate);
1475 }
1476 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1477 pathSBounds);
1478 GrIRect pathIBounds;
1479 pathSBounds.roundOut(&pathIBounds);
1480 if (!pathBounds->intersect(pathIBounds)) {
1481 return false;
1482 }
1483 } else {
1484 return false;
1485 }
1486 return true;
1487}
1488
1489/**
1490 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1491 * scratch texture.
1492 */
1493
1494bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1495 const GrIRect& pathDevBounds,
1496 GrPathFill fill,
1497 GrContext* context,
1498 const GrPoint* translate,
1499 GrAutoScratchTexture* tex) {
1500 SkPaint paint;
1501 SkPath tmpPath;
1502 const SkPath* pathToDraw = &clientPath;
1503 if (kHairLine_PathFill == fill) {
1504 paint.setStyle(SkPaint::kStroke_Style);
1505 paint.setStrokeWidth(SK_Scalar1);
1506 } else {
1507 paint.setStyle(SkPaint::kFill_Style);
1508 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1509 if (skfill != pathToDraw->getFillType()) {
1510 tmpPath = *pathToDraw;
1511 tmpPath.setFillType(skfill);
1512 pathToDraw = &tmpPath;
1513 }
1514 }
1515 paint.setAntiAlias(true);
1516 paint.setColor(SK_ColorWHITE);
1517
1518 GrMatrix matrix = context->getMatrix();
1519 if (NULL != translate) {
1520 matrix.postTranslate(translate->fX, translate->fY);
1521 }
1522
1523 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1524 -pathDevBounds.fTop * SK_Scalar1);
1525 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1526 pathDevBounds.height());
1527
1528 SkBitmap bm;
1529 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1530 if (!bm.allocPixels()) {
1531 return false;
1532 }
1533 sk_bzero(bm.getPixels(), bm.getSafeSize());
1534
1535 SkDraw draw;
1536 sk_bzero(&draw, sizeof(draw));
1537 SkRasterClip rc(bounds);
1538 draw.fRC = &rc;
1539 draw.fClip = &rc.bwRgn();
1540 draw.fMatrix = &matrix;
1541 draw.fBitmap = &bm;
1542 draw.drawPath(*pathToDraw, paint);
1543
1544 const GrTextureDesc desc = {
1545 kNone_GrTextureFlags,
1546 kNone_GrAALevel,
1547 bounds.fRight,
1548 bounds.fBottom,
1549 kAlpha_8_GrPixelConfig
1550 };
1551
1552 tex->set(context, desc);
1553 GrTexture* texture = tex->texture();
1554
1555 if (NULL == texture) {
1556 return false;
1557 }
1558 SkAutoLockPixels alp(bm);
1559 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1560 bm.getPixels(), bm.rowBytes());
1561 return true;
1562}
1563
1564void draw_around_inv_path(GrDrawTarget* target,
1565 GrDrawState::StageMask stageMask,
1566 const GrIRect& clipBounds,
1567 const GrIRect& pathBounds) {
1568 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1569 GrRect rect;
1570 if (clipBounds.fTop < pathBounds.fTop) {
1571 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1572 clipBounds.fRight, pathBounds.fTop);
1573 target->drawSimpleRect(rect, NULL, stageMask);
1574 }
1575 if (clipBounds.fLeft < pathBounds.fLeft) {
1576 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1577 pathBounds.fLeft, pathBounds.fBottom);
1578 target->drawSimpleRect(rect, NULL, stageMask);
1579 }
1580 if (clipBounds.fRight > pathBounds.fRight) {
1581 rect.iset(pathBounds.fRight, pathBounds.fTop,
1582 clipBounds.fRight, pathBounds.fBottom);
1583 target->drawSimpleRect(rect, NULL, stageMask);
1584 }
1585 if (clipBounds.fBottom > pathBounds.fBottom) {
1586 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1587 clipBounds.fRight, clipBounds.fBottom);
1588 target->drawSimpleRect(rect, NULL, stageMask);
1589 }
1590}
1591
1592}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001593
reed@google.com07f3ee12011-05-16 17:21:57 +00001594void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1595 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001596
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001597 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001598 if (GrIsFillInverted(fill)) {
1599 this->drawPaint(paint);
1600 }
1601 return;
1602 }
1603
bsalomon@google.com27847de2011-02-22 20:59:41 +00001604 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001605 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001606
bsalomon@google.com289533a2011-10-27 12:34:25 +00001607 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1608
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001609 // An Assumption here is that path renderer would use some form of tweaking
1610 // the src color (either the input alpha or in the frag shader) to implement
1611 // aa. If we have some future driver-mojo path AA that can do the right
1612 // thing WRT to the blend then we'll need some query on the PR.
1613 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001614#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001615 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001616#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001617 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001618 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001619
1620 bool doOSAA = false;
1621 GrPathRenderer* pr = NULL;
1622 if (prAA) {
1623 pr = this->getPathRenderer(path, fill, true);
1624 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001625 GrAutoScratchTexture ast;
1626 GrIRect pathBounds, clipBounds;
1627 if (!get_path_and_clip_bounds(target, path, translate,
1628 &pathBounds, &clipBounds)) {
1629 return;
1630 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001631 prAA = false;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001632 if (this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
1633 pr = this->getPathRenderer(path, fill, false);
1634 doOSAA = true;
1635 }
1636 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1637 fill, this,
1638 translate, &ast)) {
1639 GrTexture* texture = ast.texture();
1640 GrAssert(NULL != texture);
1641 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1642 enum {
1643 kPathMaskStage = GrPaint::kTotalStages,
1644 };
1645 target->drawState()->setTexture(kPathMaskStage, texture);
1646 target->drawState()->sampler(kPathMaskStage)->reset();
1647 GrScalar w = GrIntToScalar(pathBounds.width());
1648 GrScalar h = GrIntToScalar(pathBounds.height());
1649 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1650 h / texture->height());
1651 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1652 srcRects[kPathMaskStage] = &maskRect;
1653 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001654 GrRect dstRect = GrRect::MakeLTRB(
1655 SK_Scalar1* pathBounds.fLeft,
1656 SK_Scalar1* pathBounds.fTop,
1657 SK_Scalar1* pathBounds.fRight,
1658 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001659 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1660 target->drawState()->setTexture(kPathMaskStage, NULL);
1661 if (GrIsFillInverted(fill)) {
1662 draw_around_inv_path(target, stageMask,
1663 clipBounds, pathBounds);
1664 }
1665 return;
1666 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001667 }
1668 } else {
1669 pr = this->getPathRenderer(path, fill, false);
1670 }
1671
bsalomon@google.com30085192011-08-19 15:42:31 +00001672 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001673#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001674 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001675#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001676 return;
1677 }
1678
bsalomon@google.com289533a2011-10-27 12:34:25 +00001679 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001680
bsalomon@google.com289533a2011-10-27 12:34:25 +00001681 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001682 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001683 GrIRect pathBounds;
1684 GrIRect clipBounds;
1685 if (!get_path_and_clip_bounds(target, path, translate,
1686 &pathBounds, &clipBounds)) {
1687 return;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001688 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001689 OffscreenRecord record;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001690 if (this->prepareForOffscreenAA(target, needsStencil, pathBounds,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001691 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001692 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1693 for (int ty = 0; ty < record.fTileCountY; ++ty) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001694 this->setupOffscreenAAPass1(target, pathBounds,
1695 tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001696 pr->drawPath(0);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001697 this->doOffscreenAAPass2(target, paint, pathBounds,
1698 tx, ty, &record);
bsalomon@google.com91958362011-06-13 17:58:13 +00001699 }
1700 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001701 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001702 if (GrIsFillInverted(fill)) {
1703 draw_around_inv_path(target, stageMask, clipBounds, pathBounds);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001704 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001705 return;
1706 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001707 }
1708 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001709}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001710
bsalomon@google.com27847de2011-02-22 20:59:41 +00001711////////////////////////////////////////////////////////////////////////////////
1712
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001713void GrContext::flush(int flagsBitfield) {
1714 if (kDiscard_FlushBit & flagsBitfield) {
1715 fDrawBuffer->reset();
1716 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001717 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001718 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001719 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001720 fGpu->forceRenderTargetFlush();
1721 }
1722}
1723
1724void GrContext::flushText() {
1725 if (kText_DrawCategory == fLastDrawCategory) {
1726 flushDrawBuffer();
1727 }
1728}
1729
1730void GrContext::flushDrawBuffer() {
1731#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001732 if (fDrawBuffer) {
1733 fDrawBuffer->playback(fGpu);
1734 fDrawBuffer->reset();
1735 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001736#endif
1737}
1738
bsalomon@google.com6f379512011-11-16 20:36:03 +00001739void GrContext::internalWriteTexturePixels(GrTexture* texture,
1740 int left, int top,
1741 int width, int height,
1742 GrPixelConfig config,
1743 const void* buffer,
1744 size_t rowBytes,
1745 uint32_t flags) {
1746 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001747 ASSERT_OWNED_RESOURCE(texture);
1748
bsalomon@google.com6f379512011-11-16 20:36:03 +00001749 if (!(kDontFlush_PixelOpsFlag & flags)) {
1750 this->flush();
1751 }
1752 // TODO: use scratch texture to perform conversion
1753 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1754 GrPixelConfigIsUnpremultiplied(config)) {
1755 return;
1756 }
1757
1758 fGpu->writeTexturePixels(texture, left, top, width, height,
1759 config, buffer, rowBytes);
1760}
1761
1762bool GrContext::internalReadTexturePixels(GrTexture* texture,
1763 int left, int top,
1764 int width, int height,
1765 GrPixelConfig config,
1766 void* buffer,
1767 size_t rowBytes,
1768 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001769 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001770 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001771
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001772 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001773 GrRenderTarget* target = texture->asRenderTarget();
1774 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001775 return this->internalReadRenderTargetPixels(target,
1776 left, top, width, height,
1777 config, buffer, rowBytes,
1778 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001779 } else {
1780 return false;
1781 }
1782}
1783
bsalomon@google.com6f379512011-11-16 20:36:03 +00001784bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1785 int left, int top,
1786 int width, int height,
1787 GrPixelConfig config,
1788 void* buffer,
1789 size_t rowBytes,
1790 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001791 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001792 ASSERT_OWNED_RESOURCE(target);
1793
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001794 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001795 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001796 if (NULL == target) {
1797 return false;
1798 }
1799 }
1800
1801 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1802 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1803 // not supported at this time.
1804 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1805 !GrPixelConfigIsUnpremultiplied(config)) {
1806 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001807 }
1808
bsalomon@google.com6f379512011-11-16 20:36:03 +00001809 if (!(kDontFlush_PixelOpsFlag & flags)) {
1810 this->flush();
1811 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001812
1813 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001814 bool swapRAndB = NULL != src &&
1815 fGpu->preferredReadPixelsConfig(config) ==
1816 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001817
1818 bool flipY = NULL != src &&
1819 fGpu->readPixelsWillPayForYFlip(target, left, top,
1820 width, height, config,
1821 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001822 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1823 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001824
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001825 if (NULL == src && alphaConversion) {
1826 // we should fallback to cpu conversion here. This could happen when
1827 // we were given an external render target by the client that is not
1828 // also a texture (e.g. FBO 0 in GL)
1829 return false;
1830 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001831 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001832 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001833 if (flipY || swapRAndB || alphaConversion) {
1834 GrAssert(NULL != src);
1835 if (swapRAndB) {
1836 config = GrPixelConfigSwapRAndB(config);
1837 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001838 }
1839 // Make the scratch a render target because we don't have a robust
1840 // readTexturePixels as of yet (it calls this function).
1841 const GrTextureDesc desc = {
1842 kRenderTarget_GrTextureFlagBit,
1843 kNone_GrAALevel,
1844 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001845 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001846 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001847
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001848 // When a full readback is faster than a partial we could always make
1849 // the scratch exactly match the passed rect. However, if we see many
1850 // different size rectangles we will trash our texture cache and pay the
1851 // cost of creating and destroying many textures. So, we only request
1852 // an exact match when the caller is reading an entire RT.
1853 ScratchTexMatch match = kApprox_ScratchTexMatch;
1854 if (0 == left &&
1855 0 == top &&
1856 target->width() == width &&
1857 target->height() == height &&
1858 fGpu->fullReadPixelsIsFasterThanPartial()) {
1859 match = kExact_ScratchTexMatch;
1860 }
1861 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001862 GrTexture* texture = ast.texture();
1863 if (!texture) {
1864 return false;
1865 }
1866 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001867 GrAssert(NULL != target);
1868
1869 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001870 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001871 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001872 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001873
bsalomon@google.comc4364992011-11-07 15:54:49 +00001874 GrMatrix matrix;
1875 if (flipY) {
1876 matrix.setTranslate(SK_Scalar1 * left,
1877 SK_Scalar1 * (top + height));
1878 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1879 } else {
1880 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1881 }
1882 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001883 drawState->sampler(0)->reset(matrix);
1884 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001885 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001886 GrRect rect;
1887 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1888 fGpu->drawSimpleRect(rect, NULL, 0x1);
1889 left = 0;
1890 top = 0;
1891 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001892 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001893 left, top, width, height,
1894 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001895}
1896
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001897void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1898 if (NULL == src || NULL == dst) {
1899 return;
1900 }
1901 ASSERT_OWNED_RESOURCE(src);
1902
1903 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001904 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001905 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001906 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001907 GrMatrix sampleM;
1908 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001909 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001910 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001911 SkRect rect = SkRect::MakeXYWH(0, 0,
1912 SK_Scalar1 * src->width(),
1913 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001914 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1915}
1916
bsalomon@google.com6f379512011-11-16 20:36:03 +00001917void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1918 int left, int top,
1919 int width, int height,
1920 GrPixelConfig config,
1921 const void* buffer,
1922 size_t rowBytes,
1923 uint32_t flags) {
1924 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001925 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001926
1927 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001928 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001929 if (NULL == target) {
1930 return;
1931 }
1932 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001933
1934 // TODO: when underlying api has a direct way to do this we should use it
1935 // (e.g. glDrawPixels on desktop GL).
1936
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001937 // If the RT is also a texture and we don't have to do PM/UPM conversion
1938 // then take the texture path, which we expect to be at least as fast or
1939 // faster since it doesn't use an intermediate texture as we do below.
1940
1941#if !GR_MAC_BUILD
1942 // At least some drivers on the Mac get confused when glTexImage2D is called
1943 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1944 // determine what OS versions and/or HW is affected.
1945 if (NULL != target->asTexture() &&
1946 GrPixelConfigIsUnpremultiplied(target->config()) ==
1947 GrPixelConfigIsUnpremultiplied(config)) {
1948
1949 this->internalWriteTexturePixels(target->asTexture(),
1950 left, top, width, height,
1951 config, buffer, rowBytes, flags);
1952 return;
1953 }
1954#endif
1955
1956 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1957 GrPixelConfigSwapRAndB(config);
1958 if (swapRAndB) {
1959 config = GrPixelConfigSwapRAndB(config);
1960 }
1961
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001962 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001963 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001964 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001965 GrAutoScratchTexture ast(this, desc);
1966 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001967 if (NULL == texture) {
1968 return;
1969 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001970 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1971 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001972
bsalomon@google.com27847de2011-02-22 20:59:41 +00001973 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001974 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001975 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001976
1977 GrMatrix matrix;
1978 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001979 drawState->setViewMatrix(matrix);
1980 drawState->setRenderTarget(target);
1981 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982
bsalomon@google.com5c638652011-07-18 19:31:59 +00001983 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001984 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1985 GrSamplerState::kNearest_Filter,
1986 matrix);
1987 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001988
1989 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1990 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001991 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001992 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1993 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001994 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001995 return;
1996 }
1997 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1998 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1999}
2000////////////////////////////////////////////////////////////////////////////////
2001
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002002void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002003 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002004
2005 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
2006 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002007 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002008 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002009 if (paint.getTexture(i)) {
2010 *drawState->sampler(s) = paint.getTextureSampler(i);
2011 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002012 }
2013
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002014 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002015
2016 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
2017 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002018 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002019 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002020 if (paint.getMask(i)) {
2021 *drawState->sampler(s) = paint.getMaskSampler(i);
2022 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002023 }
2024
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002025 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002026
2027 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002028 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002029 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002030 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002031 }
2032 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002033 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002034 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002035 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002036 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002037 if (paint.fColorMatrixEnabled) {
2038 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
2039 } else {
2040 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
2041 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002042 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002043 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002044 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comdd1be602012-01-18 20:34:00 +00002045 drawState->setCoverage(paint.fCoverage);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00002046
2047 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
2048 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
2049 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002050}
2051
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002052GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002053 DrawCategory category) {
2054 if (category != fLastDrawCategory) {
2055 flushDrawBuffer();
2056 fLastDrawCategory = category;
2057 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002058 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002059 GrDrawTarget* target = fGpu;
2060 switch (category) {
2061 case kText_DrawCategory:
2062#if DEFER_TEXT_RENDERING
2063 target = fDrawBuffer;
2064 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2065#else
2066 target = fGpu;
2067#endif
2068 break;
2069 case kUnbuffered_DrawCategory:
2070 target = fGpu;
2071 break;
2072 case kBuffered_DrawCategory:
2073 target = fDrawBuffer;
2074 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2075 break;
2076 }
2077 return target;
2078}
2079
bsalomon@google.com289533a2011-10-27 12:34:25 +00002080GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
2081 GrPathFill fill,
2082 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00002083 if (NULL == fPathRendererChain) {
2084 fPathRendererChain =
2085 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
2086 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00002087 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
2088 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00002089}
2090
bsalomon@google.com27847de2011-02-22 20:59:41 +00002091////////////////////////////////////////////////////////////////////////////////
2092
bsalomon@google.com27847de2011-02-22 20:59:41 +00002093void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002094 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002095 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002096 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002097}
2098
2099GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002100 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002101}
2102
2103const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002104 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002105}
2106
2107const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002108 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002109}
2110
2111void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002112 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002113}
2114
2115void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002116 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002117}
2118
2119static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2120 intptr_t mask = 1 << shift;
2121 if (pred) {
2122 bits |= mask;
2123 } else {
2124 bits &= ~mask;
2125 }
2126 return bits;
2127}
2128
2129void GrContext::resetStats() {
2130 fGpu->resetStats();
2131}
2132
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002133const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002134 return fGpu->getStats();
2135}
2136
2137void GrContext::printStats() const {
2138 fGpu->printStats();
2139}
2140
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002141GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002142 fGpu = gpu;
2143 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002144 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002145
bsalomon@google.com30085192011-08-19 15:42:31 +00002146 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002147
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002148 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2149 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002150 fFontCache = new GrFontCache(fGpu);
2151
2152 fLastDrawCategory = kUnbuffered_DrawCategory;
2153
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002154 fDrawBuffer = NULL;
2155 fDrawBufferVBAllocPool = NULL;
2156 fDrawBufferIBAllocPool = NULL;
2157
bsalomon@google.com205d4602011-04-25 12:43:45 +00002158 fAAFillRectIndexBuffer = NULL;
2159 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002160
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002161 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2162 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002163 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2164 }
2165 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002166
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002167 this->setupDrawBuffer();
2168}
2169
2170void GrContext::setupDrawBuffer() {
2171
2172 GrAssert(NULL == fDrawBuffer);
2173 GrAssert(NULL == fDrawBufferVBAllocPool);
2174 GrAssert(NULL == fDrawBufferIBAllocPool);
2175
bsalomon@google.com27847de2011-02-22 20:59:41 +00002176#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002177 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002178 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002179 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2180 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002181 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002182 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002183 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002184 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2185
bsalomon@google.com471d4712011-08-23 15:45:25 +00002186 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2187 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002188 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002189#endif
2190
2191#if BATCH_RECT_TO_RECT
2192 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2193#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002194}
2195
bsalomon@google.com27847de2011-02-22 20:59:41 +00002196GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2197 GrDrawTarget* target;
2198#if DEFER_TEXT_RENDERING
2199 target = prepareToDraw(paint, kText_DrawCategory);
2200#else
2201 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2202#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002203 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002204 return target;
2205}
2206
2207const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2208 return fGpu->getQuadIndexBuffer();
2209}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002210
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002211void GrContext::convolveInX(GrTexture* texture,
2212 const SkRect& rect,
2213 const float* kernel,
2214 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002215 ASSERT_OWNED_RESOURCE(texture);
2216
bsalomon@google.com99621082011-11-15 16:47:16 +00002217 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002218 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2219}
2220
2221void GrContext::convolveInY(GrTexture* texture,
2222 const SkRect& rect,
2223 const float* kernel,
2224 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002225 ASSERT_OWNED_RESOURCE(texture);
2226
bsalomon@google.com99621082011-11-15 16:47:16 +00002227 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002228 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2229}
2230
2231void GrContext::convolve(GrTexture* texture,
2232 const SkRect& rect,
2233 float imageIncrement[2],
2234 const float* kernel,
2235 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002236 ASSERT_OWNED_RESOURCE(texture);
2237
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002238 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002239 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.comdd1be602012-01-18 20:34:00 +00002240 GrRenderTarget* target = drawState->getRenderTarget();
2241 drawState->reset();
2242 drawState->setRenderTarget(target);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002243 GrMatrix sampleM;
2244 sampleM.setIDiv(texture->width(), texture->height());
2245 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2246 GrSamplerState::kConvolution_Filter,
2247 sampleM);
2248 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2249 kernel,
2250 imageIncrement);
2251
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002252 drawState->setTexture(0, texture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002253 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2254}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002255
2256///////////////////////////////////////////////////////////////////////////////