blob: 6ffda118547833433be8549722c25a34934d84d1 [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
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000021#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000022#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023
bsalomon@google.com91958362011-06-13 17:58:13 +000024// Using MSAA seems to be slower for some yet unknown reason.
25#define PREFER_MSAA_OFFSCREEN_AA 0
26#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000027
bsalomon@google.com27847de2011-02-22 20:59:41 +000028#define DEFER_TEXT_RENDERING 1
29
30#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
bsalomon@google.comd46e2422011-09-23 17:40:07 +000032// When we're using coverage AA but the blend is incompatible (given gpu
33// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000034#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000035
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000036static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
37static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000038
39static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
40static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
41
42// We are currently only batching Text and drawRectToRect, both
43// of which use the quad index buffer.
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
46
bsalomon@google.com05ef5102011-05-02 21:14:59 +000047GrContext* GrContext::Create(GrEngine engine,
48 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000049 GrContext* ctx = NULL;
50 GrGpu* fGpu = GrGpu::Create(engine, context3D);
51 if (NULL != fGpu) {
52 ctx = new GrContext(fGpu);
53 fGpu->unref();
54 }
55 return ctx;
56}
57
58GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000059 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000060}
61
62GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000063 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000064 delete fTextureCache;
65 delete fFontCache;
66 delete fDrawBuffer;
67 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000068 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000069
bsalomon@google.com205d4602011-04-25 12:43:45 +000070 GrSafeUnref(fAAFillRectIndexBuffer);
71 GrSafeUnref(fAAStrokeRectIndexBuffer);
72 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000073 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com30085192011-08-19 15:42:31 +000086 // a path renderer may be holding onto resources that
87 // are now unusable
88 GrSafeSetNull(fPathRendererChain);
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 delete fDrawBuffer;
91 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000092
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 delete fDrawBufferVBAllocPool;
94 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000095
bsalomon@google.com8fe72472011-03-30 21:26:44 +000096 delete fDrawBufferIBAllocPool;
97 fDrawBufferIBAllocPool = NULL;
98
bsalomon@google.com205d4602011-04-25 12:43:45 +000099 GrSafeSetNull(fAAFillRectIndexBuffer);
100 GrSafeSetNull(fAAStrokeRectIndexBuffer);
101
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102 fTextureCache->removeAll();
103 fFontCache->freeAll();
104 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000105}
106
107void GrContext::resetContext() {
108 fGpu->markContextDirty();
109}
110
111void GrContext::freeGpuResources() {
112 this->flush();
113 fTextureCache->removeAll();
114 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000115 // a path renderer may be holding onto resources
116 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000117}
118
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000119////////////////////////////////////////////////////////////////////////////////
120
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000121int GrContext::PaintStageVertexLayoutBits(
122 const GrPaint& paint,
123 const bool hasTexCoords[GrPaint::kTotalStages]) {
124 int stageMask = paint.getActiveStageMask();
125 int layout = 0;
126 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
127 if ((1 << i) & stageMask) {
128 if (NULL != hasTexCoords && hasTexCoords[i]) {
129 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
130 } else {
131 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
132 }
133 }
134 }
135 return layout;
136}
137
138
139////////////////////////////////////////////////////////////////////////////////
140
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000141enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000142 // flags for textures
143 kNPOTBit = 0x1,
144 kFilterBit = 0x2,
145 kScratchBit = 0x4,
146
147 // resource type
148 kTextureBit = 0x8,
149 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000150};
151
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000152GrTexture* GrContext::TextureCacheEntry::texture() const {
153 if (NULL == fEntry) {
154 return NULL;
155 } else {
156 return (GrTexture*) fEntry->resource();
157 }
158}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000159
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000160namespace {
161// returns true if this is a "special" texture because of gpu NPOT limitations
162bool gen_texture_key_values(const GrGpu* gpu,
163 const GrSamplerState& sampler,
164 GrContext::TextureKey clientKey,
165 int width,
166 int height,
167 bool scratch,
168 uint32_t v[4]) {
169 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
170 // we assume we only need 16 bits of width and height
171 // assert that texture creation will fail anyway if this assumption
172 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000173 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000174 v[0] = clientKey & 0xffffffffUL;
175 v[1] = (clientKey >> 32) & 0xffffffffUL;
176 v[2] = width | (height << 16);
177
178 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000179 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000180 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
181
182 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
183 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
184
185 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +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.comfea37b52011-04-25 15:51:06 +0000217}
218
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000219GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
220 int width,
221 int height,
222 const GrSamplerState& sampler) {
223 uint32_t v[4];
224 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
225 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000226 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
227 GrResourceCache::kNested_LockType));
228}
229
230GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
231 uint32_t v[4];
232 gen_stencil_key_values(sb, v);
233 GrResourceKey resourceKey(v);
234 return fTextureCache->createAndLock(resourceKey, sb);
235}
236
237GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
238 int sampleCnt) {
239 uint32_t v[4];
240 gen_stencil_key_values(width, height, sampleCnt, v);
241 GrResourceKey resourceKey(v);
242 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
243 GrResourceCache::kSingle_LockType);
244 if (NULL != entry) {
245 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
246 return sb;
247 } else {
248 return NULL;
249 }
250}
251
252void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
253 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000254}
255
256static void stretchImage(void* dst,
257 int dstW,
258 int dstH,
259 void* src,
260 int srcW,
261 int srcH,
262 int bpp) {
263 GrFixed dx = (srcW << 16) / dstW;
264 GrFixed dy = (srcH << 16) / dstH;
265
266 GrFixed y = dy >> 1;
267
268 int dstXLimit = dstW*bpp;
269 for (int j = 0; j < dstH; ++j) {
270 GrFixed x = dx >> 1;
271 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
272 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
273 for (int i = 0; i < dstXLimit; i += bpp) {
274 memcpy((uint8_t*) dstRow + i,
275 (uint8_t*) srcRow + (x>>16)*bpp,
276 bpp);
277 x += dx;
278 }
279 y += dy;
280 }
281}
282
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000283GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000284 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000285 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000286 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000287 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000288
289#if GR_DUMP_TEXTURE_UPLOAD
290 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
291#endif
292
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000293 TextureCacheEntry entry;
294 uint32_t v[4];
295 bool special = gen_texture_key_values(fGpu, sampler, key,
296 desc.fWidth, desc.fHeight, false, v);
297 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000298
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000299 if (special) {
300 TextureCacheEntry clampEntry =
301 findAndLockTexture(key, desc.fWidth, desc.fHeight,
302 GrSamplerState::ClampNoFilter());
303
304 if (NULL == clampEntry.texture()) {
305 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000306 GrSamplerState::ClampNoFilter(),
307 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000308 GrAssert(NULL != clampEntry.texture());
309 if (NULL == clampEntry.texture()) {
310 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000311 }
312 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000313 GrTextureDesc rtDesc = desc;
314 rtDesc.fFlags = rtDesc.fFlags |
315 kRenderTarget_GrTextureFlagBit |
316 kNoStencil_GrTextureFlagBit;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000317 rtDesc.fWidth =
318 GrNextPow2(GrMax<int>(desc.fWidth,
319 fGpu->getCaps().fMinRenderTargetWidth));
320 rtDesc.fHeight =
321 GrNextPow2(GrMax<int>(desc.fHeight,
322 fGpu->getCaps().fMinRenderTargetHeight));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000323
324 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
325
326 if (NULL != texture) {
327 GrDrawTarget::AutoStateRestore asr(fGpu);
328 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000329 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000330 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000331 fGpu->setViewMatrix(GrMatrix::I());
332 fGpu->setAlpha(0xff);
333 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
334 fGpu->disableState(GrDrawTarget::kDither_StateBit |
335 GrDrawTarget::kClip_StateBit |
336 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000337 GrSamplerState::Filter filter;
338 // if filtering is not desired then we want to ensure all
339 // texels in the resampled image are copies of texels from
340 // the original.
341 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
342 filter = GrSamplerState::kNearest_Filter;
343 } else {
344 filter = GrSamplerState::kBilinear_Filter;
345 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000346 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
347 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000348 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000349 fGpu->setSamplerState(0, stretchSampler);
350
351 static const GrVertexLayout layout =
352 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
353 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
354
355 if (arg.succeeded()) {
356 GrPoint* verts = (GrPoint*) arg.vertices();
357 verts[0].setIRectFan(0, 0,
358 texture->width(),
359 texture->height(),
360 2*sizeof(GrPoint));
361 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
362 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
363 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000364 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000365 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000366 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000367 } else {
368 // TODO: Our CPU stretch doesn't filter. But we create separate
369 // stretched textures when the sampler state is either filtered or
370 // not. Either implement filtered stretch blit on CPU or just create
371 // one when FBO case fails.
372
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000373 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000374 // no longer need to clamp at min RT size.
375 rtDesc.fWidth = GrNextPow2(desc.fWidth);
376 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000377 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000378 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000379 rtDesc.fWidth *
380 rtDesc.fHeight);
381 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
382 srcData, desc.fWidth, desc.fHeight, bpp);
383
384 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
385
386 GrTexture* texture = fGpu->createTexture(rtDesc,
387 stretchedPixels.get(),
388 stretchedRowBytes);
389 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000390 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000392 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000393
394 } else {
395 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
396 if (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 }
399 }
400 return entry;
401}
402
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403namespace {
404inline void gen_scratch_tex_key_values(const GrGpu* gpu,
405 const GrTextureDesc& desc,
406 uint32_t v[4]) {
407 // Instead of a client-provided key of the texture contents
408 // we create a key of from the descriptor.
409 GrContext::TextureKey descKey = desc.fAALevel |
410 (desc.fFlags << 8) |
411 ((uint64_t) desc.fFormat << 32);
412 // this code path isn't friendly to tiling with NPOT restricitons
413 // We just pass ClampNoFilter()
414 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
415 desc.fWidth, desc.fHeight, true, v);
416}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000417}
418
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000419GrContext::TextureCacheEntry GrContext::lockScratchTexture(
420 const GrTextureDesc& inDesc,
421 ScratchTexMatch match) {
422
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000423 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000424 if (kExact_ScratchTexMatch != match) {
425 // bin by pow2 with a reasonable min
426 static const int MIN_SIZE = 256;
427 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
428 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
429 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000430
431 uint32_t p0 = desc.fFormat;
432 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
433
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000435 int origWidth = desc.fWidth;
436 int origHeight = desc.fHeight;
437 bool doubledW = false;
438 bool doubledH = false;
439
440 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441 uint32_t v[4];
442 gen_scratch_tex_key_values(fGpu, desc, v);
443 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000444 entry = fTextureCache->findAndLock(key,
445 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000446 // if we miss, relax the fit of the flags...
447 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000448 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000449 break;
450 }
451 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
452 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
453 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
454 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
455 } else if (!doubledW) {
456 desc.fFlags = inDesc.fFlags;
457 desc.fWidth *= 2;
458 doubledW = true;
459 } else if (!doubledH) {
460 desc.fFlags = inDesc.fFlags;
461 desc.fWidth = origWidth;
462 desc.fHeight *= 2;
463 doubledH = true;
464 } else {
465 break;
466 }
467
468 } while (true);
469
470 if (NULL == entry) {
471 desc.fFlags = inDesc.fFlags;
472 desc.fWidth = origWidth;
473 desc.fHeight = origHeight;
474 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
475 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000476 uint32_t v[4];
477 gen_scratch_tex_key_values(fGpu, desc, v);
478 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000479 entry = fTextureCache->createAndLock(key, texture);
480 }
481 }
482
483 // If the caller gives us the same desc/sampler twice we don't want
484 // to return the same texture the second time (unless it was previously
485 // released). So we detach the entry from the cache and reattach at release.
486 if (NULL != entry) {
487 fTextureCache->detach(entry);
488 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000489 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000490}
491
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000492void GrContext::unlockTexture(TextureCacheEntry entry) {
493 // If this is a scratch texture we detached it from the cache
494 // while it was locked (to avoid two callers simultaneously getting
495 // the same texture).
496 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
497 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000498 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000499 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000500 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000501}
502
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000503GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000504 void* srcData,
505 size_t rowBytes) {
506 return fGpu->createTexture(desc, srcData, rowBytes);
507}
508
509void GrContext::getTextureCacheLimits(int* maxTextures,
510 size_t* maxTextureBytes) const {
511 fTextureCache->getLimits(maxTextures, maxTextureBytes);
512}
513
514void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
515 fTextureCache->setLimits(maxTextures, maxTextureBytes);
516}
517
bsalomon@google.com91958362011-06-13 17:58:13 +0000518int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000519 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000520}
521
522int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000523 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000524}
525
526///////////////////////////////////////////////////////////////////////////////
527
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000528GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
529 // validate flags here so that GrGpu subclasses don't have to check
530 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
531 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000532 return NULL;
533 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000534 if (desc.fSampleCnt &&
535 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000536 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000537 }
538 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
539 desc.fSampleCnt &&
540 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
541 return NULL;
542 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000543 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000544}
545
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000546///////////////////////////////////////////////////////////////////////////////
547
bsalomon@google.com27847de2011-02-22 20:59:41 +0000548bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000549 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000550 const GrDrawTarget::Caps& caps = fGpu->getCaps();
551 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000552 return false;
553 }
554
bsalomon@google.com27847de2011-02-22 20:59:41 +0000555 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
556
557 if (!isPow2) {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000558 if (!caps.fNPOTTextureSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000559 return false;
560 }
561
562 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
563 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000564 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000565 return false;
566 }
567 }
568 return true;
569}
570
571////////////////////////////////////////////////////////////////////////////////
572
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000573const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
574
bsalomon@google.com27847de2011-02-22 20:59:41 +0000575void GrContext::setClip(const GrClip& clip) {
576 fGpu->setClip(clip);
577 fGpu->enableState(GrDrawTarget::kClip_StateBit);
578}
579
580void GrContext::setClip(const GrIRect& rect) {
581 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000582 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000583 fGpu->setClip(clip);
584}
585
586////////////////////////////////////////////////////////////////////////////////
587
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000588void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000589 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000590 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000591}
592
593void GrContext::drawPaint(const GrPaint& paint) {
594 // set rect to be big enough to fill the space, but not super-huge, so we
595 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000596 GrRect r;
597 r.setLTRB(0, 0,
598 GrIntToScalar(getRenderTarget()->width()),
599 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000600 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000601 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000602 SkTLazy<GrPaint> tmpPaint;
603 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000604 // We attempt to map r by the inverse matrix and draw that. mapRect will
605 // map the four corners and bound them with a new rect. This will not
606 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000607 if (!this->getMatrix().hasPerspective()) {
608 if (!fGpu->getViewInverse(&inverse)) {
609 GrPrintf("Could not invert matrix");
610 return;
611 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000612 inverse.mapRect(&r);
613 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000614 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
615 if (!fGpu->getViewInverse(&inverse)) {
616 GrPrintf("Could not invert matrix");
617 return;
618 }
619 tmpPaint.set(paint);
620 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
621 p = tmpPaint.get();
622 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000623 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000624 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000625 // by definition this fills the entire clip, no need for AA
626 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000627 if (!tmpPaint.isValid()) {
628 tmpPaint.set(paint);
629 p = tmpPaint.get();
630 }
631 GrAssert(p == tmpPaint.get());
632 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000633 }
634 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000635}
636
bsalomon@google.com205d4602011-04-25 12:43:45 +0000637////////////////////////////////////////////////////////////////////////////////
638
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000639namespace {
640inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
641 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
642}
643}
644
bsalomon@google.com91958362011-06-13 17:58:13 +0000645struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000646 enum Downsample {
647 k4x4TwoPass_Downsample,
648 k4x4SinglePass_Downsample,
649 kFSAA_Downsample
650 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000651 int fTileSizeX;
652 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000653 int fTileCountX;
654 int fTileCountY;
655 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000656 GrAutoScratchTexture fOffscreen0;
657 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000658 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000659 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000660};
661
bsalomon@google.com471d4712011-08-23 15:45:25 +0000662bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000663 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000664#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000665 return false;
666#else
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000667 if (!target->isAntialiasState()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000668 return false;
669 }
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000670 // Line primitves are always rasterized as 1 pixel wide.
671 // Super-sampling would make them too thin but MSAA would be OK.
672 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000673 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000674 return false;
675 }
676 if (target->getRenderTarget()->isMultisampled()) {
677 return false;
678 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000679 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000680#if GR_DEBUG
bsalomon@google.coma3108262011-10-10 14:08:47 +0000681 GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000682#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000683 return false;
684 }
685 return true;
686#endif
687}
688
bsalomon@google.com91958362011-06-13 17:58:13 +0000689bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000690 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000691 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000692 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000693 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000694
695 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000696
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000697 GrAssert(NULL == record->fOffscreen0.texture());
698 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000699 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000700
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000701 int boundW = boundRect.width();
702 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000703
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000704 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000705
706 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
707 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
708
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000709 if (requireStencil) {
710 desc.fFlags = kRenderTarget_GrTextureFlagBit;
711 } else {
712 desc.fFlags = kRenderTarget_GrTextureFlagBit |
713 kNoStencil_GrTextureFlagBit;
714 }
715
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000716 desc.fFormat = kRGBA_8888_GrPixelConfig;
717
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000718 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000719 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000720 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000721 desc.fAALevel = kMed_GrAALevel;
722 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000723 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000724 OffscreenRecord::k4x4SinglePass_Downsample :
725 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000726 record->fScale = OFFSCREEN_SSAA_SCALE;
727 // both downsample paths assume this
728 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000729 desc.fAALevel = kNone_GrAALevel;
730 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000731
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000732 desc.fWidth *= record->fScale;
733 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000734 record->fOffscreen0.set(this, desc);
735 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000736 return false;
737 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000738 // the approximate lookup might have given us some slop space, might as well
739 // use it when computing the tiles size.
740 // these are scale values, will adjust after considering
741 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000742 record->fTileSizeX = record->fOffscreen0.texture()->width();
743 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000744
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000745 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000746 desc.fWidth /= 2;
747 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000748 record->fOffscreen1.set(this, desc);
749 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000750 return false;
751 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000752 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000753 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000754 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000755 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000756 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000757 record->fTileSizeX /= record->fScale;
758 record->fTileSizeY /= record->fScale;
759
760 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
761 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
762
tomhudson@google.com237a4612011-07-19 15:44:00 +0000763 record->fClip = target->getClip();
764
bsalomon@google.com91958362011-06-13 17:58:13 +0000765 target->saveCurrentDrawState(&record->fSavedState);
766 return true;
767}
768
769void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
770 const GrIRect& boundRect,
771 int tileX, int tileY,
772 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000773
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000774 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000775 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000776
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000777 GrPaint tempPaint;
778 tempPaint.reset();
779 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000780 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000781
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000782 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000783 int left = boundRect.fLeft + tileX * record->fTileSizeX;
784 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000785 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000786 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000787 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000788 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000789 target->postConcatViewMatrix(scaleM);
790
bsalomon@google.com91958362011-06-13 17:58:13 +0000791 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000792 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000793 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000794 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000795 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
796 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000797 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000798#if 0
799 // visualize tile boundaries by setting edges of offscreen to white
800 // and interior to tranparent. black.
801 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000802
bsalomon@google.com91958362011-06-13 17:58:13 +0000803 static const int gOffset = 2;
804 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
805 record->fScale * w - gOffset,
806 record->fScale * h - gOffset);
807 target->clear(&clear2, 0x0);
808#else
809 target->clear(&clear, 0x0);
810#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000811}
812
bsalomon@google.com91958362011-06-13 17:58:13 +0000813void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000814 const GrPaint& paint,
815 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000816 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000817 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000818 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000819 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000820 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000821 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000822 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
823 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000824 tileRect.fRight = (tileX == record->fTileCountX-1) ?
825 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000826 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000827 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
828 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000829 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000830
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000831 GrSamplerState::Filter filter;
832 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
833 filter = GrSamplerState::k4x4Downsample_Filter;
834 } else {
835 filter = GrSamplerState::kBilinear_Filter;
836 }
837
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000838 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000839 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000840 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000841
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000842 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000843 int scale;
844
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000845 enum {
846 kOffscreenStage = GrPaint::kTotalStages,
847 };
848
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000849 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000850 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000852 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000853
854 // Do 2x2 downsample from first to second
855 target->setTexture(kOffscreenStage, src);
856 target->setRenderTarget(dst);
857 target->setViewMatrix(GrMatrix::I());
858 sampleM.setScale(scale * GR_Scalar1 / src->width(),
859 scale * GR_Scalar1 / src->height());
860 sampler.setMatrix(sampleM);
861 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000862 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
863 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
865
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000866 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000867 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000868 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000869 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000870 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000871 } else {
872 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
873 record->fDownsample);
874 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000875 }
876
bsalomon@google.com91958362011-06-13 17:58:13 +0000877 // setup for draw back to main RT, we use the original
878 // draw state setup by the caller plus an additional coverage
879 // stage to handle the AA resolve. Also, we use an identity
880 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000881 int stageMask = paint.getActiveStageMask();
882
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000883 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000884 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000885
886 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000887 GrMatrix invVM;
888 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000889 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000890 }
891 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000892 // This is important when tiling, otherwise second tile's
893 // pass 1 view matrix will be incorrect.
894 GrDrawTarget::AutoViewMatrixRestore avmr(target);
895
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000896 target->setViewMatrix(GrMatrix::I());
897
898 target->setTexture(kOffscreenStage, src);
899 sampleM.setScale(scale * GR_Scalar1 / src->width(),
900 scale * GR_Scalar1 / src->height());
901 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000902 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
903 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000904 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000905 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000906
reed@google.com20efde72011-05-09 17:00:02 +0000907 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000908 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000909 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000910 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000911}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000912
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000913void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
914 GrPathRenderer* pr,
915 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000916 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000917}
918
919////////////////////////////////////////////////////////////////////////////////
920
bsalomon@google.com27847de2011-02-22 20:59:41 +0000921/* create a triangle strip that strokes the specified triangle. There are 8
922 unique vertices, but we repreat the last 2 to close up. Alternatively we
923 could use an indices array, and then only send 8 verts, but not sure that
924 would be faster.
925 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000926static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000927 GrScalar width) {
928 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000929 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000930
931 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
932 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
933 verts[2].set(rect.fRight - rad, rect.fTop + rad);
934 verts[3].set(rect.fRight + rad, rect.fTop - rad);
935 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
936 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
937 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
938 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
939 verts[8] = verts[0];
940 verts[9] = verts[1];
941}
942
bsalomon@google.com205d4602011-04-25 12:43:45 +0000943static void setInsetFan(GrPoint* pts, size_t stride,
944 const GrRect& r, GrScalar dx, GrScalar dy) {
945 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
946}
947
948static const uint16_t gFillAARectIdx[] = {
949 0, 1, 5, 5, 4, 0,
950 1, 2, 6, 6, 5, 1,
951 2, 3, 7, 7, 6, 2,
952 3, 0, 4, 4, 7, 3,
953 4, 5, 6, 6, 7, 4,
954};
955
956int GrContext::aaFillRectIndexCount() const {
957 return GR_ARRAY_COUNT(gFillAARectIdx);
958}
959
960GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
961 if (NULL == fAAFillRectIndexBuffer) {
962 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
963 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000964 if (NULL != fAAFillRectIndexBuffer) {
965 #if GR_DEBUG
966 bool updated =
967 #endif
968 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
969 sizeof(gFillAARectIdx));
970 GR_DEBUGASSERT(updated);
971 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000972 }
973 return fAAFillRectIndexBuffer;
974}
975
976static const uint16_t gStrokeAARectIdx[] = {
977 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
978 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
979 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
980 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
981
982 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
983 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
984 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
985 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
986
987 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
988 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
989 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
990 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
991};
992
993int GrContext::aaStrokeRectIndexCount() const {
994 return GR_ARRAY_COUNT(gStrokeAARectIdx);
995}
996
997GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
998 if (NULL == fAAStrokeRectIndexBuffer) {
999 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1000 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001001 if (NULL != fAAStrokeRectIndexBuffer) {
1002 #if GR_DEBUG
1003 bool updated =
1004 #endif
1005 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1006 sizeof(gStrokeAARectIdx));
1007 GR_DEBUGASSERT(updated);
1008 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001009 }
1010 return fAAStrokeRectIndexBuffer;
1011}
1012
bsalomon@google.coma3108262011-10-10 14:08:47 +00001013static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1014 bool useCoverage) {
1015 GrVertexLayout layout = 0;
1016 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
1017 if (NULL != target->getTexture(s)) {
1018 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1019 }
1020 }
1021 if (useCoverage) {
1022 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1023 } else {
1024 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1025 }
1026 return layout;
1027}
1028
bsalomon@google.com205d4602011-04-25 12:43:45 +00001029void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001030 const GrRect& devRect,
1031 bool useVertexCoverage) {
1032 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001033
1034 size_t vsize = GrDrawTarget::VertexSize(layout);
1035
1036 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001037 if (!geo.succeeded()) {
1038 GrPrintf("Failed to get space for vertices!\n");
1039 return;
1040 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001041 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1042 if (NULL == indexBuffer) {
1043 GrPrintf("Failed to create index buffer!\n");
1044 return;
1045 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001046
1047 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1048
1049 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1050 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1051
1052 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1053 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1054
1055 verts += sizeof(GrPoint);
1056 for (int i = 0; i < 4; ++i) {
1057 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1058 }
1059
bsalomon@google.coma3108262011-10-10 14:08:47 +00001060 GrColor innerColor;
1061 if (useVertexCoverage) {
1062 innerColor = GrColorPackRGBA(0,0,0,0xff);
1063 } else {
1064 innerColor = target->getColor();
1065 }
1066
bsalomon@google.com205d4602011-04-25 12:43:45 +00001067 verts += 4 * vsize;
1068 for (int i = 0; i < 4; ++i) {
1069 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1070 }
1071
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001072 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001073
1074 target->drawIndexed(kTriangles_PrimitiveType, 0,
1075 0, 8, this->aaFillRectIndexCount());
1076}
1077
bsalomon@google.coma3108262011-10-10 14:08:47 +00001078void GrContext::strokeAARect(GrDrawTarget* target,
1079 const GrRect& devRect,
1080 const GrVec& devStrokeSize,
1081 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001082 const GrScalar& dx = devStrokeSize.fX;
1083 const GrScalar& dy = devStrokeSize.fY;
1084 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1085 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1086
bsalomon@google.com205d4602011-04-25 12:43:45 +00001087 GrScalar spare;
1088 {
1089 GrScalar w = devRect.width() - dx;
1090 GrScalar h = devRect.height() - dy;
1091 spare = GrMin(w, h);
1092 }
1093
1094 if (spare <= 0) {
1095 GrRect r(devRect);
1096 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001097 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001098 return;
1099 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001100 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001101 size_t vsize = GrDrawTarget::VertexSize(layout);
1102
1103 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001104 if (!geo.succeeded()) {
1105 GrPrintf("Failed to get space for vertices!\n");
1106 return;
1107 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001108 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1109 if (NULL == indexBuffer) {
1110 GrPrintf("Failed to create index buffer!\n");
1111 return;
1112 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001113
1114 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1115
1116 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1117 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1118 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1119 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1120
1121 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1122 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1123 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1124 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1125
1126 verts += sizeof(GrPoint);
1127 for (int i = 0; i < 4; ++i) {
1128 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1129 }
1130
bsalomon@google.coma3108262011-10-10 14:08:47 +00001131 GrColor innerColor;
1132 if (useVertexCoverage) {
1133 innerColor = GrColorPackRGBA(0,0,0,0xff);
1134 } else {
1135 innerColor = target->getColor();
1136 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001137 verts += 4 * vsize;
1138 for (int i = 0; i < 8; ++i) {
1139 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1140 }
1141
1142 verts += 8 * vsize;
1143 for (int i = 0; i < 8; ++i) {
1144 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1145 }
1146
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001147 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001148 target->drawIndexed(kTriangles_PrimitiveType,
1149 0, 0, 16, aaStrokeRectIndexCount());
1150}
1151
reed@google.com20efde72011-05-09 17:00:02 +00001152/**
1153 * Returns true if the rects edges are integer-aligned.
1154 */
1155static bool isIRect(const GrRect& r) {
1156 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1157 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1158}
1159
bsalomon@google.com205d4602011-04-25 12:43:45 +00001160static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001161 const GrRect& rect,
1162 GrScalar width,
1163 const GrMatrix* matrix,
1164 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001165 GrRect* devRect,
1166 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001167 // we use a simple alpha ramp to do aa on axis-aligned rects
1168 // do AA with alpha ramp if the caller requested AA, the rect
1169 // will be axis-aligned,the render target is not
1170 // multisampled, and the rect won't land on integer coords.
1171
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001172 if (!target->isAntialiasState()) {
1173 return false;
1174 }
1175
bsalomon@google.coma3108262011-10-10 14:08:47 +00001176 // we are keeping around the "tweak the alpha" trick because
1177 // it is our only hope for the fixed-pipe implementation.
1178 // In a shader implementation we can give a separate coverage input
1179 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001180 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001181 if (target->getCaps().fSupportPerVertexCoverage) {
1182 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001183#if GR_DEBUG
bsalomon@google.coma3108262011-10-10 14:08:47 +00001184 GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001185#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001186 return false;
1187 } else {
1188 *useVertexCoverage = true;
1189 }
1190 } else {
1191 GrPrintf("Rect AA dropped because no support for coverage.\n");
1192 return false;
1193 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001194 }
1195
1196 if (target->getRenderTarget()->isMultisampled()) {
1197 return false;
1198 }
1199
bsalomon@google.com471d4712011-08-23 15:45:25 +00001200 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001201 return false;
1202 }
1203
1204 if (!target->getViewMatrix().preservesAxisAlignment()) {
1205 return false;
1206 }
1207
1208 if (NULL != matrix &&
1209 !matrix->preservesAxisAlignment()) {
1210 return false;
1211 }
1212
1213 *combinedMatrix = target->getViewMatrix();
1214 if (NULL != matrix) {
1215 combinedMatrix->preConcat(*matrix);
1216 GrAssert(combinedMatrix->preservesAxisAlignment());
1217 }
1218
1219 combinedMatrix->mapRect(devRect, rect);
1220 devRect->sort();
1221
1222 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001223 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001224 } else {
1225 return true;
1226 }
1227}
1228
bsalomon@google.com27847de2011-02-22 20:59:41 +00001229void GrContext::drawRect(const GrPaint& paint,
1230 const GrRect& rect,
1231 GrScalar width,
1232 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001233 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234
1235 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001236 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001237
bsalomon@google.com205d4602011-04-25 12:43:45 +00001238 GrRect devRect = rect;
1239 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001240 bool useVertexCoverage;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001241 bool doAA = apply_aa_to_rect(target, rect, width, matrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001242 &combinedMatrix, &devRect, &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001243
1244 if (doAA) {
1245 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001246 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001247 GrMatrix inv;
1248 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001249 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001250 }
1251 }
1252 target->setViewMatrix(GrMatrix::I());
1253 if (width >= 0) {
1254 GrVec strokeSize;;
1255 if (width > 0) {
1256 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001257 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001258 strokeSize.setAbs(strokeSize);
1259 } else {
1260 strokeSize.set(GR_Scalar1, GR_Scalar1);
1261 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001262 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001263 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001264 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001265 }
1266 return;
1267 }
1268
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269 if (width >= 0) {
1270 // TODO: consider making static vertex buffers for these cases.
1271 // Hairline could be done by just adding closing vertex to
1272 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001273 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1274
bsalomon@google.com27847de2011-02-22 20:59:41 +00001275 static const int worstCaseVertCount = 10;
1276 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1277
1278 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001279 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001280 return;
1281 }
1282
1283 GrPrimitiveType primType;
1284 int vertCount;
1285 GrPoint* vertex = geo.positions();
1286
1287 if (width > 0) {
1288 vertCount = 10;
1289 primType = kTriangleStrip_PrimitiveType;
1290 setStrokeRectStrip(vertex, rect, width);
1291 } else {
1292 // hairline
1293 vertCount = 5;
1294 primType = kLineStrip_PrimitiveType;
1295 vertex[0].set(rect.fLeft, rect.fTop);
1296 vertex[1].set(rect.fRight, rect.fTop);
1297 vertex[2].set(rect.fRight, rect.fBottom);
1298 vertex[3].set(rect.fLeft, rect.fBottom);
1299 vertex[4].set(rect.fLeft, rect.fTop);
1300 }
1301
1302 GrDrawTarget::AutoViewMatrixRestore avmr;
1303 if (NULL != matrix) {
1304 avmr.set(target);
1305 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001306 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001307 }
1308
1309 target->drawNonIndexed(primType, 0, vertCount);
1310 } else {
1311 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001312 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001313 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1314 if (NULL == sqVB) {
1315 GrPrintf("Failed to create static rect vb.\n");
1316 return;
1317 }
1318 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001319 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1320 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001321 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001322 0, rect.height(), rect.fTop,
1323 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324
1325 if (NULL != matrix) {
1326 m.postConcat(*matrix);
1327 }
1328
1329 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001330 target->preConcatSamplerMatrices(stageMask, m);
1331
bsalomon@google.com27847de2011-02-22 20:59:41 +00001332 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1333 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001334 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001335 #endif
1336 }
1337}
1338
1339void GrContext::drawRectToRect(const GrPaint& paint,
1340 const GrRect& dstRect,
1341 const GrRect& srcRect,
1342 const GrMatrix* dstMatrix,
1343 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001344 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001345
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001346 // srcRect refers to paint's first texture
1347 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001348 drawRect(paint, dstRect, -1, dstMatrix);
1349 return;
1350 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001351
bsalomon@google.com27847de2011-02-22 20:59:41 +00001352 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1353
1354#if GR_STATIC_RECT_VB
1355 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001356
1357 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001358 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1359
1360 GrMatrix m;
1361
1362 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1363 0, dstRect.height(), dstRect.fTop,
1364 0, 0, GrMatrix::I()[8]);
1365 if (NULL != dstMatrix) {
1366 m.postConcat(*dstMatrix);
1367 }
1368 target->preConcatViewMatrix(m);
1369
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001370 // srcRect refers to first stage
1371 int otherStageMask = paint.getActiveStageMask() &
1372 (~(1 << GrPaint::kFirstTextureStage));
1373 if (otherStageMask) {
1374 target->preConcatSamplerMatrices(otherStageMask, m);
1375 }
1376
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1378 0, srcRect.height(), srcRect.fTop,
1379 0, 0, GrMatrix::I()[8]);
1380 if (NULL != srcMatrix) {
1381 m.postConcat(*srcMatrix);
1382 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001383 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001384
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001385 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1386 if (NULL == sqVB) {
1387 GrPrintf("Failed to create static rect vb.\n");
1388 return;
1389 }
1390 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001391 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1392#else
1393
1394 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001395#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001396 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001397#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1399#endif
1400
1401 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1402 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1403 srcRects[0] = &srcRect;
1404 srcMatrices[0] = srcMatrix;
1405
1406 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1407#endif
1408}
1409
1410void GrContext::drawVertices(const GrPaint& paint,
1411 GrPrimitiveType primitiveType,
1412 int vertexCount,
1413 const GrPoint positions[],
1414 const GrPoint texCoords[],
1415 const GrColor colors[],
1416 const uint16_t indices[],
1417 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001418 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001419
1420 GrDrawTarget::AutoReleaseGeometry geo;
1421
1422 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1423
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001424 bool hasTexCoords[GrPaint::kTotalStages] = {
1425 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1426 0 // remaining stages use positions
1427 };
1428
1429 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001430
1431 if (NULL != colors) {
1432 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001433 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001434 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001435
1436 if (sizeof(GrPoint) != vertexSize) {
1437 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001438 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001439 return;
1440 }
1441 int texOffsets[GrDrawTarget::kMaxTexCoords];
1442 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001443 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1444 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001445 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001446 NULL,
1447 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001448 void* curVertex = geo.vertices();
1449
1450 for (int i = 0; i < vertexCount; ++i) {
1451 *((GrPoint*)curVertex) = positions[i];
1452
1453 if (texOffsets[0] > 0) {
1454 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1455 }
1456 if (colorOffset > 0) {
1457 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1458 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001459 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460 }
1461 } else {
1462 target->setVertexSourceToArray(layout, positions, vertexCount);
1463 }
1464
bsalomon@google.com91958362011-06-13 17:58:13 +00001465 // we don't currently apply offscreen AA to this path. Need improved
1466 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001467
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001468 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001469 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001470 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001471 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001472 target->drawNonIndexed(primitiveType, 0, vertexCount);
1473 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001474}
1475
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001476///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001477
reed@google.com07f3ee12011-05-16 17:21:57 +00001478void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1479 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001480
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001481 if (path.isEmpty()) {
1482#if GR_DEBUG
1483 GrPrintf("Empty path should have been caught by canvas.\n");
1484#endif
1485 if (GrIsFillInverted(fill)) {
1486 this->drawPaint(paint);
1487 }
1488 return;
1489 }
1490
bsalomon@google.com27847de2011-02-22 20:59:41 +00001491 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001492
1493 // An Assumption here is that path renderer would use some form of tweaking
1494 // the src color (either the input alpha or in the frag shader) to implement
1495 // aa. If we have some future driver-mojo path AA that can do the right
1496 // thing WRT to the blend then we'll need some query on the PR.
1497 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001498#if GR_DEBUG
1499 GrPrintf("Turning off AA to correctly apply blend.\n")
1500#endif
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001501 target->disableState(GrDrawTarget::kAntialias_StateBit);
1502 }
1503
bsalomon@google.com30085192011-08-19 15:42:31 +00001504 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1505 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001506#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001507 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001508#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001509 return;
1510 }
1511
bsalomon@google.comee435122011-07-01 14:57:55 +00001512 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1513 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001514
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001515 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001516 this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001517
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001518 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001519
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001520 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001521 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1522 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001523 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001524 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001525 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001526 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001527 return;
1528 }
1529 }
reed@google.com70c136e2011-06-03 19:51:26 +00001530
reed@google.com07f3ee12011-05-16 17:21:57 +00001531 GrRect pathBounds = path.getBounds();
1532 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001533 if (NULL != translate) {
1534 pathBounds.offset(*translate);
1535 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001536 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001537 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001538 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001539 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001540 return;
1541 }
1542 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001543 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001544 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1545 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001546 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1547 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1548 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001549 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001550 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1551 }
1552 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001553 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001554 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001555 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1556 GrRect rect;
1557 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001558 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1559 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001560 target->drawSimpleRect(rect, NULL, stageMask);
1561 }
1562 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001563 rect.iset(clipIBounds.fLeft, bound.fTop,
1564 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001565 target->drawSimpleRect(rect, NULL, stageMask);
1566 }
1567 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001568 rect.iset(bound.fRight, bound.fTop,
1569 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001570 target->drawSimpleRect(rect, NULL, stageMask);
1571 }
1572 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001573 rect.iset(clipIBounds.fLeft, bound.fBottom,
1574 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001575 target->drawSimpleRect(rect, NULL, stageMask);
1576 }
1577 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001578 return;
1579 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001580 }
1581 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001582}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001583
bsalomon@google.com27847de2011-02-22 20:59:41 +00001584////////////////////////////////////////////////////////////////////////////////
1585
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001586bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001587 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001588}
1589
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001590void GrContext::flush(int flagsBitfield) {
1591 if (kDiscard_FlushBit & flagsBitfield) {
1592 fDrawBuffer->reset();
1593 } else {
1594 flushDrawBuffer();
1595 }
1596
1597 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001598 fGpu->forceRenderTargetFlush();
1599 }
1600}
1601
1602void GrContext::flushText() {
1603 if (kText_DrawCategory == fLastDrawCategory) {
1604 flushDrawBuffer();
1605 }
1606}
1607
1608void GrContext::flushDrawBuffer() {
1609#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001610 if (fDrawBuffer) {
1611 fDrawBuffer->playback(fGpu);
1612 fDrawBuffer->reset();
1613 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614#endif
1615}
1616
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001617bool GrContext::readTexturePixels(GrTexture* texture,
1618 int left, int top, int width, int height,
1619 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001620 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001621
1622 // TODO: code read pixels for textures that aren't rendertargets
1623
1624 this->flush();
1625 GrRenderTarget* target = texture->asRenderTarget();
1626 if (NULL != target) {
1627 return fGpu->readPixels(target,
1628 left, top, width, height,
1629 config, buffer);
1630 } else {
1631 return false;
1632 }
1633}
1634
1635bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1636 int left, int top, int width, int height,
1637 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001638 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001639 uint32_t flushFlags = 0;
1640 if (NULL == target) {
1641 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1642 }
1643
1644 this->flush(flushFlags);
1645 return fGpu->readPixels(target,
1646 left, top, width, height,
1647 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001648}
1649
1650void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001651 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001652 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001653 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001654
1655 // TODO: when underlying api has a direct way to do this we should use it
1656 // (e.g. glDrawPixels on desktop GL).
1657
bsalomon@google.com5c638652011-07-18 19:31:59 +00001658 this->flush(true);
1659
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001660 const GrTextureDesc desc = {
1661 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001662 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001663 GrAutoScratchTexture ast(this, desc);
1664 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001665 if (NULL == texture) {
1666 return;
1667 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001668 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001669
bsalomon@google.com27847de2011-02-22 20:59:41 +00001670 GrDrawTarget::AutoStateRestore asr(fGpu);
1671
1672 GrMatrix matrix;
1673 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1674 fGpu->setViewMatrix(matrix);
1675
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001676 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001677 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1678 fGpu->setAlpha(0xFF);
1679 fGpu->setBlendFunc(kOne_BlendCoeff,
1680 kZero_BlendCoeff);
1681 fGpu->setTexture(0, texture);
1682
1683 GrSamplerState sampler;
1684 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001685 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001686 sampler.setMatrix(matrix);
1687 fGpu->setSamplerState(0, sampler);
1688
1689 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1690 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001691 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001692 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1693 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001694 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001695 return;
1696 }
1697 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1698 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1699}
1700////////////////////////////////////////////////////////////////////////////////
1701
1702void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001703
1704 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1705 int s = i + GrPaint::kFirstTextureStage;
1706 target->setTexture(s, paint.getTexture(i));
1707 target->setSamplerState(s, *paint.getTextureSampler(i));
1708 }
1709
1710 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1711
1712 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1713 int s = i + GrPaint::kFirstMaskStage;
1714 target->setTexture(s, paint.getMask(i));
1715 target->setSamplerState(s, *paint.getMaskSampler(i));
1716 }
1717
bsalomon@google.com27847de2011-02-22 20:59:41 +00001718 target->setColor(paint.fColor);
1719
1720 if (paint.fDither) {
1721 target->enableState(GrDrawTarget::kDither_StateBit);
1722 } else {
1723 target->disableState(GrDrawTarget::kDither_StateBit);
1724 }
1725 if (paint.fAntiAlias) {
1726 target->enableState(GrDrawTarget::kAntialias_StateBit);
1727 } else {
1728 target->disableState(GrDrawTarget::kAntialias_StateBit);
1729 }
1730 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001731 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001732
1733 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1734 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1735 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001736}
1737
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001738GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001739 DrawCategory category) {
1740 if (category != fLastDrawCategory) {
1741 flushDrawBuffer();
1742 fLastDrawCategory = category;
1743 }
1744 SetPaint(paint, fGpu);
1745 GrDrawTarget* target = fGpu;
1746 switch (category) {
1747 case kText_DrawCategory:
1748#if DEFER_TEXT_RENDERING
1749 target = fDrawBuffer;
1750 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1751#else
1752 target = fGpu;
1753#endif
1754 break;
1755 case kUnbuffered_DrawCategory:
1756 target = fGpu;
1757 break;
1758 case kBuffered_DrawCategory:
1759 target = fDrawBuffer;
1760 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1761 break;
1762 }
1763 return target;
1764}
1765
bsalomon@google.com30085192011-08-19 15:42:31 +00001766GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1767 const GrPath& path,
1768 GrPathFill fill) {
1769 if (NULL == fPathRendererChain) {
1770 fPathRendererChain =
1771 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1772 }
1773 return fPathRendererChain->getPathRenderer(target, path, fill);
1774}
1775
bsalomon@google.com27847de2011-02-22 20:59:41 +00001776////////////////////////////////////////////////////////////////////////////////
1777
bsalomon@google.com27847de2011-02-22 20:59:41 +00001778void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001779 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001780 fGpu->setRenderTarget(target);
1781}
1782
1783GrRenderTarget* GrContext::getRenderTarget() {
1784 return fGpu->getRenderTarget();
1785}
1786
1787const GrRenderTarget* GrContext::getRenderTarget() const {
1788 return fGpu->getRenderTarget();
1789}
1790
1791const GrMatrix& GrContext::getMatrix() const {
1792 return fGpu->getViewMatrix();
1793}
1794
1795void GrContext::setMatrix(const GrMatrix& m) {
1796 fGpu->setViewMatrix(m);
1797}
1798
1799void GrContext::concatMatrix(const GrMatrix& m) const {
1800 fGpu->preConcatViewMatrix(m);
1801}
1802
1803static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1804 intptr_t mask = 1 << shift;
1805 if (pred) {
1806 bits |= mask;
1807 } else {
1808 bits &= ~mask;
1809 }
1810 return bits;
1811}
1812
1813void GrContext::resetStats() {
1814 fGpu->resetStats();
1815}
1816
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001817const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001818 return fGpu->getStats();
1819}
1820
1821void GrContext::printStats() const {
1822 fGpu->printStats();
1823}
1824
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001825GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001826 fGpu = gpu;
1827 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001828 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001829
bsalomon@google.com30085192011-08-19 15:42:31 +00001830 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001831
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001832 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1833 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001834 fFontCache = new GrFontCache(fGpu);
1835
1836 fLastDrawCategory = kUnbuffered_DrawCategory;
1837
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001838 fDrawBuffer = NULL;
1839 fDrawBufferVBAllocPool = NULL;
1840 fDrawBufferIBAllocPool = NULL;
1841
bsalomon@google.com205d4602011-04-25 12:43:45 +00001842 fAAFillRectIndexBuffer = NULL;
1843 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001844
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001845 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1846 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001847 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1848 }
1849 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001850
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001851 this->setupDrawBuffer();
1852}
1853
1854void GrContext::setupDrawBuffer() {
1855
1856 GrAssert(NULL == fDrawBuffer);
1857 GrAssert(NULL == fDrawBufferVBAllocPool);
1858 GrAssert(NULL == fDrawBufferIBAllocPool);
1859
bsalomon@google.com27847de2011-02-22 20:59:41 +00001860#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001861 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001862 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001863 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1864 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001865 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001866 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001867 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1869
bsalomon@google.com471d4712011-08-23 15:45:25 +00001870 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1871 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001872 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001873#endif
1874
1875#if BATCH_RECT_TO_RECT
1876 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1877#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001878}
1879
bsalomon@google.com27847de2011-02-22 20:59:41 +00001880GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1881 GrDrawTarget* target;
1882#if DEFER_TEXT_RENDERING
1883 target = prepareToDraw(paint, kText_DrawCategory);
1884#else
1885 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1886#endif
1887 SetPaint(paint, target);
1888 return target;
1889}
1890
1891const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1892 return fGpu->getQuadIndexBuffer();
1893}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001894
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001895void GrContext::convolveInX(GrTexture* texture,
1896 const SkRect& rect,
1897 const float* kernel,
1898 int kernelWidth) {
1899 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1900 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1901}
1902
1903void GrContext::convolveInY(GrTexture* texture,
1904 const SkRect& rect,
1905 const float* kernel,
1906 int kernelWidth) {
1907 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1908 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1909}
1910
1911void GrContext::convolve(GrTexture* texture,
1912 const SkRect& rect,
1913 float imageIncrement[2],
1914 const float* kernel,
1915 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001916 GrDrawTarget::AutoStateRestore asr(fGpu);
1917 GrMatrix sampleM;
1918 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1919 GrSamplerState::kClamp_WrapMode,
1920 GrSamplerState::kConvolution_Filter);
1921 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001922 sampleM.setScale(GR_Scalar1 / texture->width(),
1923 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001924 sampler.setMatrix(sampleM);
1925 fGpu->setSamplerState(0, sampler);
1926 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001927 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001928 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001929 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1930}