blob: 607ade8244df770c6127122e2e280bda365a7da0 [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 |
bsalomon@google.com289533a2011-10-27 12:34:25 +0000336 GrDrawTarget::kHWAntialias_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.com64c4fe42011-11-05 14:51:01 +0000377 int bpp = GrBytesPerPixel(desc.fConfig);
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) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000411 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412 // 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
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000431 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000432 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.com1f221a72011-08-23 20:54:07 +0000667 // Line primitves are always rasterized as 1 pixel wide.
668 // Super-sampling would make them too thin but MSAA would be OK.
669 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000670 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000671 return false;
672 }
673 if (target->getRenderTarget()->isMultisampled()) {
674 return false;
675 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000676 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000677#if GR_DEBUG
bsalomon@google.coma3108262011-10-10 14:08:47 +0000678 GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000679#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000680 return false;
681 }
682 return true;
683#endif
684}
685
bsalomon@google.com91958362011-06-13 17:58:13 +0000686bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000687 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000688 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000689 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000690 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000691
692 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000693
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000694 GrAssert(NULL == record->fOffscreen0.texture());
695 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000696 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000697
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000698 int boundW = boundRect.width();
699 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000700
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000701 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000702
703 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
704 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
705
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000706 if (requireStencil) {
707 desc.fFlags = kRenderTarget_GrTextureFlagBit;
708 } else {
709 desc.fFlags = kRenderTarget_GrTextureFlagBit |
710 kNoStencil_GrTextureFlagBit;
711 }
712
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000713 desc.fConfig = kRGBA_8888_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000714
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000715 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000716 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000717 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000718 desc.fAALevel = kMed_GrAALevel;
719 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000720 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000721 OffscreenRecord::k4x4SinglePass_Downsample :
722 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000723 record->fScale = OFFSCREEN_SSAA_SCALE;
724 // both downsample paths assume this
725 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000726 desc.fAALevel = kNone_GrAALevel;
727 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000728
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000729 desc.fWidth *= record->fScale;
730 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000731 record->fOffscreen0.set(this, desc);
732 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000733 return false;
734 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000735 // the approximate lookup might have given us some slop space, might as well
736 // use it when computing the tiles size.
737 // these are scale values, will adjust after considering
738 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000739 record->fTileSizeX = record->fOffscreen0.texture()->width();
740 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000741
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000742 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000743 desc.fWidth /= 2;
744 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000745 record->fOffscreen1.set(this, desc);
746 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000747 return false;
748 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000749 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000750 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000751 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000752 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000753 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000754 record->fTileSizeX /= record->fScale;
755 record->fTileSizeY /= record->fScale;
756
757 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
758 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
759
tomhudson@google.com237a4612011-07-19 15:44:00 +0000760 record->fClip = target->getClip();
761
bsalomon@google.com91958362011-06-13 17:58:13 +0000762 target->saveCurrentDrawState(&record->fSavedState);
763 return true;
764}
765
766void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
767 const GrIRect& boundRect,
768 int tileX, int tileY,
769 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000770
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000771 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000772 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000773
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000774 GrPaint tempPaint;
775 tempPaint.reset();
776 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000777 target->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000778#if PREFER_MSAA_OFFSCREEN_AA
779 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
780#endif
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;
tomhudson@google.com93813632011-10-27 20:21:16 +00001016 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001017 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) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001062 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001063 } 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) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001133 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001134 } 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
bsalomon@google.com289533a2011-10-27 12:34:25 +00001169 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001170
bsalomon@google.coma3108262011-10-10 14:08:47 +00001171 // we are keeping around the "tweak the alpha" trick because
1172 // it is our only hope for the fixed-pipe implementation.
1173 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001174 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001175 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001176 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001177 if (target->getCaps().fSupportPerVertexCoverage) {
1178 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001179#if GR_DEBUG
bsalomon@google.coma3108262011-10-10 14:08:47 +00001180 GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001181#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001182 return false;
1183 } else {
1184 *useVertexCoverage = true;
1185 }
1186 } else {
1187 GrPrintf("Rect AA dropped because no support for coverage.\n");
1188 return false;
1189 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001190 }
1191
1192 if (target->getRenderTarget()->isMultisampled()) {
1193 return false;
1194 }
1195
bsalomon@google.com471d4712011-08-23 15:45:25 +00001196 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001197 return false;
1198 }
1199
1200 if (!target->getViewMatrix().preservesAxisAlignment()) {
1201 return false;
1202 }
1203
1204 if (NULL != matrix &&
1205 !matrix->preservesAxisAlignment()) {
1206 return false;
1207 }
1208
1209 *combinedMatrix = target->getViewMatrix();
1210 if (NULL != matrix) {
1211 combinedMatrix->preConcat(*matrix);
1212 GrAssert(combinedMatrix->preservesAxisAlignment());
1213 }
1214
1215 combinedMatrix->mapRect(devRect, rect);
1216 devRect->sort();
1217
1218 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001219 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001220 } else {
1221 return true;
1222 }
1223}
1224
bsalomon@google.com27847de2011-02-22 20:59:41 +00001225void GrContext::drawRect(const GrPaint& paint,
1226 const GrRect& rect,
1227 GrScalar width,
1228 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001229 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001230
1231 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001232 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233
bsalomon@google.com205d4602011-04-25 12:43:45 +00001234 GrRect devRect = rect;
1235 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001236 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001237 bool needAA = paint.fAntiAlias &&
1238 !this->getRenderTarget()->isMultisampled();
1239 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1240 &combinedMatrix, &devRect,
1241 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001242
1243 if (doAA) {
1244 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001245 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001246 GrMatrix inv;
1247 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001248 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001249 }
1250 }
1251 target->setViewMatrix(GrMatrix::I());
1252 if (width >= 0) {
1253 GrVec strokeSize;;
1254 if (width > 0) {
1255 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001256 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001257 strokeSize.setAbs(strokeSize);
1258 } else {
1259 strokeSize.set(GR_Scalar1, GR_Scalar1);
1260 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001261 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001262 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001263 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001264 }
1265 return;
1266 }
1267
bsalomon@google.com27847de2011-02-22 20:59:41 +00001268 if (width >= 0) {
1269 // TODO: consider making static vertex buffers for these cases.
1270 // Hairline could be done by just adding closing vertex to
1271 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001272 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1273
bsalomon@google.com27847de2011-02-22 20:59:41 +00001274 static const int worstCaseVertCount = 10;
1275 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1276
1277 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001278 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001279 return;
1280 }
1281
1282 GrPrimitiveType primType;
1283 int vertCount;
1284 GrPoint* vertex = geo.positions();
1285
1286 if (width > 0) {
1287 vertCount = 10;
1288 primType = kTriangleStrip_PrimitiveType;
1289 setStrokeRectStrip(vertex, rect, width);
1290 } else {
1291 // hairline
1292 vertCount = 5;
1293 primType = kLineStrip_PrimitiveType;
1294 vertex[0].set(rect.fLeft, rect.fTop);
1295 vertex[1].set(rect.fRight, rect.fTop);
1296 vertex[2].set(rect.fRight, rect.fBottom);
1297 vertex[3].set(rect.fLeft, rect.fBottom);
1298 vertex[4].set(rect.fLeft, rect.fTop);
1299 }
1300
1301 GrDrawTarget::AutoViewMatrixRestore avmr;
1302 if (NULL != matrix) {
1303 avmr.set(target);
1304 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001305 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001306 }
1307
1308 target->drawNonIndexed(primType, 0, vertCount);
1309 } else {
1310 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001311 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001312 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1313 if (NULL == sqVB) {
1314 GrPrintf("Failed to create static rect vb.\n");
1315 return;
1316 }
1317 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001318 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1319 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001320 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001321 0, rect.height(), rect.fTop,
1322 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001323
1324 if (NULL != matrix) {
1325 m.postConcat(*matrix);
1326 }
1327
1328 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001329 target->preConcatSamplerMatrices(stageMask, m);
1330
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1332 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001333 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001334 #endif
1335 }
1336}
1337
1338void GrContext::drawRectToRect(const GrPaint& paint,
1339 const GrRect& dstRect,
1340 const GrRect& srcRect,
1341 const GrMatrix* dstMatrix,
1342 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001343 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001345 // srcRect refers to paint's first texture
1346 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001347 drawRect(paint, dstRect, -1, dstMatrix);
1348 return;
1349 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001350
bsalomon@google.com27847de2011-02-22 20:59:41 +00001351 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1352
1353#if GR_STATIC_RECT_VB
1354 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001355
1356 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001357 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1358
1359 GrMatrix m;
1360
1361 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1362 0, dstRect.height(), dstRect.fTop,
1363 0, 0, GrMatrix::I()[8]);
1364 if (NULL != dstMatrix) {
1365 m.postConcat(*dstMatrix);
1366 }
1367 target->preConcatViewMatrix(m);
1368
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001369 // srcRect refers to first stage
1370 int otherStageMask = paint.getActiveStageMask() &
1371 (~(1 << GrPaint::kFirstTextureStage));
1372 if (otherStageMask) {
1373 target->preConcatSamplerMatrices(otherStageMask, m);
1374 }
1375
bsalomon@google.com27847de2011-02-22 20:59:41 +00001376 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1377 0, srcRect.height(), srcRect.fTop,
1378 0, 0, GrMatrix::I()[8]);
1379 if (NULL != srcMatrix) {
1380 m.postConcat(*srcMatrix);
1381 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001382 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001383
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001384 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1385 if (NULL == sqVB) {
1386 GrPrintf("Failed to create static rect vb.\n");
1387 return;
1388 }
1389 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001390 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1391#else
1392
1393 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001394#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001396#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1398#endif
1399
tomhudson@google.com93813632011-10-27 20:21:16 +00001400 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1401 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001402 srcRects[0] = &srcRect;
1403 srcMatrices[0] = srcMatrix;
1404
1405 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1406#endif
1407}
1408
1409void GrContext::drawVertices(const GrPaint& paint,
1410 GrPrimitiveType primitiveType,
1411 int vertexCount,
1412 const GrPoint positions[],
1413 const GrPoint texCoords[],
1414 const GrColor colors[],
1415 const uint16_t indices[],
1416 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001417 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001418
1419 GrDrawTarget::AutoReleaseGeometry geo;
1420
1421 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1422
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001423 bool hasTexCoords[GrPaint::kTotalStages] = {
1424 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1425 0 // remaining stages use positions
1426 };
1427
1428 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001429
1430 if (NULL != colors) {
1431 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001432 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001433 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001434
1435 if (sizeof(GrPoint) != vertexSize) {
1436 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001437 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001438 return;
1439 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001440 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001442 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1443 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001444 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001445 NULL,
1446 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001447 void* curVertex = geo.vertices();
1448
1449 for (int i = 0; i < vertexCount; ++i) {
1450 *((GrPoint*)curVertex) = positions[i];
1451
1452 if (texOffsets[0] > 0) {
1453 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1454 }
1455 if (colorOffset > 0) {
1456 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1457 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001458 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001459 }
1460 } else {
1461 target->setVertexSourceToArray(layout, positions, vertexCount);
1462 }
1463
bsalomon@google.com91958362011-06-13 17:58:13 +00001464 // we don't currently apply offscreen AA to this path. Need improved
1465 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001466
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001467 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001468 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001469 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001470 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001471 target->drawNonIndexed(primitiveType, 0, vertexCount);
1472 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001473}
1474
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001475///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001476
reed@google.com07f3ee12011-05-16 17:21:57 +00001477void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1478 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001479
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001480 if (path.isEmpty()) {
1481#if GR_DEBUG
1482 GrPrintf("Empty path should have been caught by canvas.\n");
1483#endif
1484 if (GrIsFillInverted(fill)) {
1485 this->drawPaint(paint);
1486 }
1487 return;
1488 }
1489
bsalomon@google.com27847de2011-02-22 20:59:41 +00001490 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001491
bsalomon@google.com289533a2011-10-27 12:34:25 +00001492 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1493
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001494 // An Assumption here is that path renderer would use some form of tweaking
1495 // the src color (either the input alpha or in the frag shader) to implement
1496 // aa. If we have some future driver-mojo path AA that can do the right
1497 // thing WRT to the blend then we'll need some query on the PR.
1498 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001499#if GR_DEBUG
bsalomon@google.com077232e2011-10-10 15:27:20 +00001500 GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001501#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001502 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001503 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001504
1505 bool doOSAA = false;
1506 GrPathRenderer* pr = NULL;
1507 if (prAA) {
1508 pr = this->getPathRenderer(path, fill, true);
1509 if (NULL == pr) {
1510 prAA = false;
1511 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1512 pr = this->getPathRenderer(path, fill, false);
1513 }
1514 } else {
1515 pr = this->getPathRenderer(path, fill, false);
1516 }
1517
bsalomon@google.com30085192011-08-19 15:42:31 +00001518 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001519#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001520 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001521#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001522 return;
1523 }
1524
bsalomon@google.com289533a2011-10-27 12:34:25 +00001525 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.comee435122011-07-01 14:57:55 +00001526 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001527
bsalomon@google.com289533a2011-10-27 12:34:25 +00001528 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001529 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001530
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001531 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001532 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1533 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001534 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001535 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001536 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001537 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001538 return;
1539 }
1540 }
reed@google.com70c136e2011-06-03 19:51:26 +00001541
reed@google.com07f3ee12011-05-16 17:21:57 +00001542 GrRect pathBounds = path.getBounds();
1543 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001544 if (NULL != translate) {
1545 pathBounds.offset(*translate);
1546 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001547 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001548 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001549 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001550 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001551 return;
1552 }
1553 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001554 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001555 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1556 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001557 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1558 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1559 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001560 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001561 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1562 }
1563 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001564 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001565 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001566 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1567 GrRect rect;
1568 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001569 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1570 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001571 target->drawSimpleRect(rect, NULL, stageMask);
1572 }
1573 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001574 rect.iset(clipIBounds.fLeft, bound.fTop,
1575 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001576 target->drawSimpleRect(rect, NULL, stageMask);
1577 }
1578 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001579 rect.iset(bound.fRight, bound.fTop,
1580 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001581 target->drawSimpleRect(rect, NULL, stageMask);
1582 }
1583 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001584 rect.iset(clipIBounds.fLeft, bound.fBottom,
1585 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001586 target->drawSimpleRect(rect, NULL, stageMask);
1587 }
1588 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001589 return;
1590 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001591 }
1592 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001593}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001594
bsalomon@google.com27847de2011-02-22 20:59:41 +00001595////////////////////////////////////////////////////////////////////////////////
1596
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001597bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001598 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001599}
1600
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001601void GrContext::flush(int flagsBitfield) {
1602 if (kDiscard_FlushBit & flagsBitfield) {
1603 fDrawBuffer->reset();
1604 } else {
1605 flushDrawBuffer();
1606 }
1607
1608 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001609 fGpu->forceRenderTargetFlush();
1610 }
1611}
1612
1613void GrContext::flushText() {
1614 if (kText_DrawCategory == fLastDrawCategory) {
1615 flushDrawBuffer();
1616 }
1617}
1618
1619void GrContext::flushDrawBuffer() {
1620#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001621 if (fDrawBuffer) {
1622 fDrawBuffer->playback(fGpu);
1623 fDrawBuffer->reset();
1624 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001625#endif
1626}
1627
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001628bool GrContext::readTexturePixels(GrTexture* texture,
1629 int left, int top, int width, int height,
1630 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001631 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001632
1633 // TODO: code read pixels for textures that aren't rendertargets
1634
1635 this->flush();
1636 GrRenderTarget* target = texture->asRenderTarget();
1637 if (NULL != target) {
1638 return fGpu->readPixels(target,
1639 left, top, width, height,
bsalomon@google.comc6980972011-11-02 19:57:21 +00001640 config, buffer, 0);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001641 } else {
1642 return false;
1643 }
1644}
1645
1646bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
bsalomon@google.comc6980972011-11-02 19:57:21 +00001647 int left, int top, int width, int height,
1648 GrPixelConfig config, void* buffer,
1649 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001650 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001651 uint32_t flushFlags = 0;
1652 if (NULL == target) {
1653 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1654 }
1655
1656 this->flush(flushFlags);
1657 return fGpu->readPixels(target,
1658 left, top, width, height,
bsalomon@google.comc6980972011-11-02 19:57:21 +00001659 config, buffer, rowBytes);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001660}
1661
1662void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001663 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001664 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001665 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001666
1667 // TODO: when underlying api has a direct way to do this we should use it
1668 // (e.g. glDrawPixels on desktop GL).
1669
bsalomon@google.com5c638652011-07-18 19:31:59 +00001670 this->flush(true);
1671
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001672 const GrTextureDesc desc = {
1673 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001674 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001675 GrAutoScratchTexture ast(this, desc);
1676 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001677 if (NULL == texture) {
1678 return;
1679 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001680 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001681
bsalomon@google.com27847de2011-02-22 20:59:41 +00001682 GrDrawTarget::AutoStateRestore asr(fGpu);
1683
1684 GrMatrix matrix;
1685 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1686 fGpu->setViewMatrix(matrix);
1687
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001688 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001689 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1690 fGpu->setAlpha(0xFF);
1691 fGpu->setBlendFunc(kOne_BlendCoeff,
1692 kZero_BlendCoeff);
1693 fGpu->setTexture(0, texture);
1694
1695 GrSamplerState sampler;
1696 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001697 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001698 sampler.setMatrix(matrix);
1699 fGpu->setSamplerState(0, sampler);
1700
1701 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1702 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001703 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001704 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1705 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001706 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001707 return;
1708 }
1709 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1710 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1711}
1712////////////////////////////////////////////////////////////////////////////////
1713
1714void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001715
1716 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1717 int s = i + GrPaint::kFirstTextureStage;
1718 target->setTexture(s, paint.getTexture(i));
1719 target->setSamplerState(s, *paint.getTextureSampler(i));
1720 }
1721
1722 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1723
1724 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1725 int s = i + GrPaint::kFirstMaskStage;
1726 target->setTexture(s, paint.getMask(i));
1727 target->setSamplerState(s, *paint.getMaskSampler(i));
1728 }
1729
bsalomon@google.com27847de2011-02-22 20:59:41 +00001730 target->setColor(paint.fColor);
1731
1732 if (paint.fDither) {
1733 target->enableState(GrDrawTarget::kDither_StateBit);
1734 } else {
1735 target->disableState(GrDrawTarget::kDither_StateBit);
1736 }
1737 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001738 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001739 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001740 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001741 }
1742 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001743 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001744
1745 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1746 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1747 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001748}
1749
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001750GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001751 DrawCategory category) {
1752 if (category != fLastDrawCategory) {
1753 flushDrawBuffer();
1754 fLastDrawCategory = category;
1755 }
1756 SetPaint(paint, fGpu);
1757 GrDrawTarget* target = fGpu;
1758 switch (category) {
1759 case kText_DrawCategory:
1760#if DEFER_TEXT_RENDERING
1761 target = fDrawBuffer;
1762 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1763#else
1764 target = fGpu;
1765#endif
1766 break;
1767 case kUnbuffered_DrawCategory:
1768 target = fGpu;
1769 break;
1770 case kBuffered_DrawCategory:
1771 target = fDrawBuffer;
1772 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1773 break;
1774 }
1775 return target;
1776}
1777
bsalomon@google.com289533a2011-10-27 12:34:25 +00001778GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1779 GrPathFill fill,
1780 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001781 if (NULL == fPathRendererChain) {
1782 fPathRendererChain =
1783 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1784 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001785 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1786 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001787}
1788
bsalomon@google.com27847de2011-02-22 20:59:41 +00001789////////////////////////////////////////////////////////////////////////////////
1790
bsalomon@google.com27847de2011-02-22 20:59:41 +00001791void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001792 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001793 fGpu->setRenderTarget(target);
1794}
1795
1796GrRenderTarget* GrContext::getRenderTarget() {
1797 return fGpu->getRenderTarget();
1798}
1799
1800const GrRenderTarget* GrContext::getRenderTarget() const {
1801 return fGpu->getRenderTarget();
1802}
1803
1804const GrMatrix& GrContext::getMatrix() const {
1805 return fGpu->getViewMatrix();
1806}
1807
1808void GrContext::setMatrix(const GrMatrix& m) {
1809 fGpu->setViewMatrix(m);
1810}
1811
1812void GrContext::concatMatrix(const GrMatrix& m) const {
1813 fGpu->preConcatViewMatrix(m);
1814}
1815
1816static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1817 intptr_t mask = 1 << shift;
1818 if (pred) {
1819 bits |= mask;
1820 } else {
1821 bits &= ~mask;
1822 }
1823 return bits;
1824}
1825
1826void GrContext::resetStats() {
1827 fGpu->resetStats();
1828}
1829
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001830const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001831 return fGpu->getStats();
1832}
1833
1834void GrContext::printStats() const {
1835 fGpu->printStats();
1836}
1837
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001838GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001839 fGpu = gpu;
1840 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001841 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001842
bsalomon@google.com30085192011-08-19 15:42:31 +00001843 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001844
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001845 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1846 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001847 fFontCache = new GrFontCache(fGpu);
1848
1849 fLastDrawCategory = kUnbuffered_DrawCategory;
1850
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001851 fDrawBuffer = NULL;
1852 fDrawBufferVBAllocPool = NULL;
1853 fDrawBufferIBAllocPool = NULL;
1854
bsalomon@google.com205d4602011-04-25 12:43:45 +00001855 fAAFillRectIndexBuffer = NULL;
1856 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001857
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001858 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1859 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001860 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1861 }
1862 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001863
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001864 this->setupDrawBuffer();
1865}
1866
1867void GrContext::setupDrawBuffer() {
1868
1869 GrAssert(NULL == fDrawBuffer);
1870 GrAssert(NULL == fDrawBufferVBAllocPool);
1871 GrAssert(NULL == fDrawBufferIBAllocPool);
1872
bsalomon@google.com27847de2011-02-22 20:59:41 +00001873#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001874 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001875 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001876 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1877 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001878 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001879 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001880 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001881 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1882
bsalomon@google.com471d4712011-08-23 15:45:25 +00001883 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1884 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001885 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001886#endif
1887
1888#if BATCH_RECT_TO_RECT
1889 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1890#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001891}
1892
bsalomon@google.com27847de2011-02-22 20:59:41 +00001893GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1894 GrDrawTarget* target;
1895#if DEFER_TEXT_RENDERING
1896 target = prepareToDraw(paint, kText_DrawCategory);
1897#else
1898 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1899#endif
1900 SetPaint(paint, target);
1901 return target;
1902}
1903
1904const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1905 return fGpu->getQuadIndexBuffer();
1906}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001907
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001908void GrContext::convolveInX(GrTexture* texture,
1909 const SkRect& rect,
1910 const float* kernel,
1911 int kernelWidth) {
1912 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1913 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1914}
1915
1916void GrContext::convolveInY(GrTexture* texture,
1917 const SkRect& rect,
1918 const float* kernel,
1919 int kernelWidth) {
1920 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1921 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1922}
1923
1924void GrContext::convolve(GrTexture* texture,
1925 const SkRect& rect,
1926 float imageIncrement[2],
1927 const float* kernel,
1928 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001929 GrDrawTarget::AutoStateRestore asr(fGpu);
1930 GrMatrix sampleM;
1931 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1932 GrSamplerState::kClamp_WrapMode,
1933 GrSamplerState::kConvolution_Filter);
1934 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001935 sampleM.setScale(GR_Scalar1 / texture->width(),
1936 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001937 sampler.setMatrix(sampleM);
1938 fGpu->setSamplerState(0, sampler);
1939 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001940 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001941 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001942 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1943}