blob: 8dbd411ebe8d9b7590abd50e56e67625ddb1cfca [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.come269f212011-11-07 13:29:52 +0000528GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
529 return fGpu->createPlatformTexture(desc);
530}
531
532GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
533 return fGpu->createPlatformRenderTarget(desc);
534}
535
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000536GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
537 // validate flags here so that GrGpu subclasses don't have to check
538 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
539 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000540 return NULL;
541 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000542 if (desc.fSampleCnt &&
543 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000544 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000545 }
546 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
547 desc.fSampleCnt &&
548 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
549 return NULL;
550 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000551 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000552}
553
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000554///////////////////////////////////////////////////////////////////////////////
555
bsalomon@google.com27847de2011-02-22 20:59:41 +0000556bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000557 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000558 const GrDrawTarget::Caps& caps = fGpu->getCaps();
559 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000560 return false;
561 }
562
bsalomon@google.com27847de2011-02-22 20:59:41 +0000563 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
564
565 if (!isPow2) {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000566 if (!caps.fNPOTTextureSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000567 return false;
568 }
569
570 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
571 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000572 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000573 return false;
574 }
575 }
576 return true;
577}
578
579////////////////////////////////////////////////////////////////////////////////
580
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000581const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
582
bsalomon@google.com27847de2011-02-22 20:59:41 +0000583void GrContext::setClip(const GrClip& clip) {
584 fGpu->setClip(clip);
585 fGpu->enableState(GrDrawTarget::kClip_StateBit);
586}
587
588void GrContext::setClip(const GrIRect& rect) {
589 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000590 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000591 fGpu->setClip(clip);
592}
593
594////////////////////////////////////////////////////////////////////////////////
595
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000596void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000597 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000598 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000599}
600
601void GrContext::drawPaint(const GrPaint& paint) {
602 // set rect to be big enough to fill the space, but not super-huge, so we
603 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000604 GrRect r;
605 r.setLTRB(0, 0,
606 GrIntToScalar(getRenderTarget()->width()),
607 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000608 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000609 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000610 SkTLazy<GrPaint> tmpPaint;
611 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000612 // We attempt to map r by the inverse matrix and draw that. mapRect will
613 // map the four corners and bound them with a new rect. This will not
614 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000615 if (!this->getMatrix().hasPerspective()) {
616 if (!fGpu->getViewInverse(&inverse)) {
617 GrPrintf("Could not invert matrix");
618 return;
619 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000620 inverse.mapRect(&r);
621 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000622 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
623 if (!fGpu->getViewInverse(&inverse)) {
624 GrPrintf("Could not invert matrix");
625 return;
626 }
627 tmpPaint.set(paint);
628 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
629 p = tmpPaint.get();
630 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000631 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000632 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000633 // by definition this fills the entire clip, no need for AA
634 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000635 if (!tmpPaint.isValid()) {
636 tmpPaint.set(paint);
637 p = tmpPaint.get();
638 }
639 GrAssert(p == tmpPaint.get());
640 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000641 }
642 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000643}
644
bsalomon@google.com205d4602011-04-25 12:43:45 +0000645////////////////////////////////////////////////////////////////////////////////
646
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000647namespace {
648inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
649 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
650}
651}
652
bsalomon@google.com91958362011-06-13 17:58:13 +0000653struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000654 enum Downsample {
655 k4x4TwoPass_Downsample,
656 k4x4SinglePass_Downsample,
657 kFSAA_Downsample
658 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000659 int fTileSizeX;
660 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000661 int fTileCountX;
662 int fTileCountY;
663 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000664 GrAutoScratchTexture fOffscreen0;
665 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000666 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000667 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000668};
669
bsalomon@google.com471d4712011-08-23 15:45:25 +0000670bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000671 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000672#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000673 return false;
674#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000675 // Line primitves are always rasterized as 1 pixel wide.
676 // Super-sampling would make them too thin but MSAA would be OK.
677 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000678 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000679 return false;
680 }
681 if (target->getRenderTarget()->isMultisampled()) {
682 return false;
683 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000684 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000685#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000686 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000687#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000688 return false;
689 }
690 return true;
691#endif
692}
693
bsalomon@google.com91958362011-06-13 17:58:13 +0000694bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000695 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000696 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000697 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000698 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000699
700 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000701
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000702 GrAssert(NULL == record->fOffscreen0.texture());
703 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000704 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000705
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000706 int boundW = boundRect.width();
707 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000708
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000709 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000710
711 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
712 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
713
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000714 if (requireStencil) {
715 desc.fFlags = kRenderTarget_GrTextureFlagBit;
716 } else {
717 desc.fFlags = kRenderTarget_GrTextureFlagBit |
718 kNoStencil_GrTextureFlagBit;
719 }
720
bsalomon@google.comc4364992011-11-07 15:54:49 +0000721 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000722
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000723 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000724 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000725 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000726 desc.fAALevel = kMed_GrAALevel;
727 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000728 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000729 OffscreenRecord::k4x4SinglePass_Downsample :
730 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000731 record->fScale = OFFSCREEN_SSAA_SCALE;
732 // both downsample paths assume this
733 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000734 desc.fAALevel = kNone_GrAALevel;
735 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000736
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000737 desc.fWidth *= record->fScale;
738 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000739 record->fOffscreen0.set(this, desc);
740 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000741 return false;
742 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000743 // the approximate lookup might have given us some slop space, might as well
744 // use it when computing the tiles size.
745 // these are scale values, will adjust after considering
746 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000747 record->fTileSizeX = record->fOffscreen0.texture()->width();
748 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000749
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000750 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000751 desc.fWidth /= 2;
752 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000753 record->fOffscreen1.set(this, desc);
754 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000755 return false;
756 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000757 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000758 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000759 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000760 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000761 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000762 record->fTileSizeX /= record->fScale;
763 record->fTileSizeY /= record->fScale;
764
765 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
766 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
767
tomhudson@google.com237a4612011-07-19 15:44:00 +0000768 record->fClip = target->getClip();
769
bsalomon@google.com91958362011-06-13 17:58:13 +0000770 target->saveCurrentDrawState(&record->fSavedState);
771 return true;
772}
773
774void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
775 const GrIRect& boundRect,
776 int tileX, int tileY,
777 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000778
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000779 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000780 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000781
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000782 GrPaint tempPaint;
783 tempPaint.reset();
784 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000785 target->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000786#if PREFER_MSAA_OFFSCREEN_AA
787 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
788#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000789
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000790 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000791 int left = boundRect.fLeft + tileX * record->fTileSizeX;
792 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000793 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000794 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000795 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000796 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000797 target->postConcatViewMatrix(scaleM);
798
bsalomon@google.com91958362011-06-13 17:58:13 +0000799 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000800 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000801 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000802 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000803 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
804 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000805 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000806#if 0
807 // visualize tile boundaries by setting edges of offscreen to white
808 // and interior to tranparent. black.
809 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000810
bsalomon@google.com91958362011-06-13 17:58:13 +0000811 static const int gOffset = 2;
812 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
813 record->fScale * w - gOffset,
814 record->fScale * h - gOffset);
815 target->clear(&clear2, 0x0);
816#else
817 target->clear(&clear, 0x0);
818#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000819}
820
bsalomon@google.com91958362011-06-13 17:58:13 +0000821void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000822 const GrPaint& paint,
823 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000824 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000825 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000826 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000827 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000828 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000829 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000830 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
831 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000832 tileRect.fRight = (tileX == record->fTileCountX-1) ?
833 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000834 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000835 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
836 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000837 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000838
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000839 GrSamplerState::Filter filter;
840 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
841 filter = GrSamplerState::k4x4Downsample_Filter;
842 } else {
843 filter = GrSamplerState::kBilinear_Filter;
844 }
845
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000846 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000847 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000848 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000849
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000850 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 int scale;
852
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000853 enum {
854 kOffscreenStage = GrPaint::kTotalStages,
855 };
856
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000857 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000858 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000859 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000860 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000861
862 // Do 2x2 downsample from first to second
863 target->setTexture(kOffscreenStage, src);
864 target->setRenderTarget(dst);
865 target->setViewMatrix(GrMatrix::I());
866 sampleM.setScale(scale * GR_Scalar1 / src->width(),
867 scale * GR_Scalar1 / src->height());
868 sampler.setMatrix(sampleM);
869 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000870 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
871 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
873
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000874 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000875 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000876 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000877 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000878 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000879 } else {
880 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
881 record->fDownsample);
882 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000883 }
884
bsalomon@google.com91958362011-06-13 17:58:13 +0000885 // setup for draw back to main RT, we use the original
886 // draw state setup by the caller plus an additional coverage
887 // stage to handle the AA resolve. Also, we use an identity
888 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000889 int stageMask = paint.getActiveStageMask();
890
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000891 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000892 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000893
894 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000895 GrMatrix invVM;
896 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000897 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000898 }
899 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000900 // This is important when tiling, otherwise second tile's
901 // pass 1 view matrix will be incorrect.
902 GrDrawTarget::AutoViewMatrixRestore avmr(target);
903
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000904 target->setViewMatrix(GrMatrix::I());
905
906 target->setTexture(kOffscreenStage, src);
907 sampleM.setScale(scale * GR_Scalar1 / src->width(),
908 scale * GR_Scalar1 / src->height());
909 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000910 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
911 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000912 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000913 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000914
reed@google.com20efde72011-05-09 17:00:02 +0000915 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000916 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000917 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000918 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000919}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000920
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000921void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
922 GrPathRenderer* pr,
923 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000924 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000925}
926
927////////////////////////////////////////////////////////////////////////////////
928
bsalomon@google.com27847de2011-02-22 20:59:41 +0000929/* create a triangle strip that strokes the specified triangle. There are 8
930 unique vertices, but we repreat the last 2 to close up. Alternatively we
931 could use an indices array, and then only send 8 verts, but not sure that
932 would be faster.
933 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000934static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000935 GrScalar width) {
936 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000937 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000938
939 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
940 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
941 verts[2].set(rect.fRight - rad, rect.fTop + rad);
942 verts[3].set(rect.fRight + rad, rect.fTop - rad);
943 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
944 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
945 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
946 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
947 verts[8] = verts[0];
948 verts[9] = verts[1];
949}
950
bsalomon@google.com205d4602011-04-25 12:43:45 +0000951static void setInsetFan(GrPoint* pts, size_t stride,
952 const GrRect& r, GrScalar dx, GrScalar dy) {
953 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
954}
955
956static const uint16_t gFillAARectIdx[] = {
957 0, 1, 5, 5, 4, 0,
958 1, 2, 6, 6, 5, 1,
959 2, 3, 7, 7, 6, 2,
960 3, 0, 4, 4, 7, 3,
961 4, 5, 6, 6, 7, 4,
962};
963
964int GrContext::aaFillRectIndexCount() const {
965 return GR_ARRAY_COUNT(gFillAARectIdx);
966}
967
968GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
969 if (NULL == fAAFillRectIndexBuffer) {
970 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
971 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000972 if (NULL != fAAFillRectIndexBuffer) {
973 #if GR_DEBUG
974 bool updated =
975 #endif
976 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
977 sizeof(gFillAARectIdx));
978 GR_DEBUGASSERT(updated);
979 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000980 }
981 return fAAFillRectIndexBuffer;
982}
983
984static const uint16_t gStrokeAARectIdx[] = {
985 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
986 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
987 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
988 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
989
990 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
991 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
992 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
993 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
994
995 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
996 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
997 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
998 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
999};
1000
1001int GrContext::aaStrokeRectIndexCount() const {
1002 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1003}
1004
1005GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1006 if (NULL == fAAStrokeRectIndexBuffer) {
1007 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1008 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001009 if (NULL != fAAStrokeRectIndexBuffer) {
1010 #if GR_DEBUG
1011 bool updated =
1012 #endif
1013 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1014 sizeof(gStrokeAARectIdx));
1015 GR_DEBUGASSERT(updated);
1016 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001017 }
1018 return fAAStrokeRectIndexBuffer;
1019}
1020
bsalomon@google.coma3108262011-10-10 14:08:47 +00001021static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1022 bool useCoverage) {
1023 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001024 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001025 if (NULL != target->getTexture(s)) {
1026 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1027 }
1028 }
1029 if (useCoverage) {
1030 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1031 } else {
1032 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1033 }
1034 return layout;
1035}
1036
bsalomon@google.com205d4602011-04-25 12:43:45 +00001037void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001038 const GrRect& devRect,
1039 bool useVertexCoverage) {
1040 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001041
1042 size_t vsize = GrDrawTarget::VertexSize(layout);
1043
1044 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001045 if (!geo.succeeded()) {
1046 GrPrintf("Failed to get space for vertices!\n");
1047 return;
1048 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001049 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1050 if (NULL == indexBuffer) {
1051 GrPrintf("Failed to create index buffer!\n");
1052 return;
1053 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001054
1055 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1056
1057 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1058 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1059
1060 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1061 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1062
1063 verts += sizeof(GrPoint);
1064 for (int i = 0; i < 4; ++i) {
1065 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1066 }
1067
bsalomon@google.coma3108262011-10-10 14:08:47 +00001068 GrColor innerColor;
1069 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001070 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001071 } else {
1072 innerColor = target->getColor();
1073 }
1074
bsalomon@google.com205d4602011-04-25 12:43:45 +00001075 verts += 4 * vsize;
1076 for (int i = 0; i < 4; ++i) {
1077 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1078 }
1079
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001080 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001081
1082 target->drawIndexed(kTriangles_PrimitiveType, 0,
1083 0, 8, this->aaFillRectIndexCount());
1084}
1085
bsalomon@google.coma3108262011-10-10 14:08:47 +00001086void GrContext::strokeAARect(GrDrawTarget* target,
1087 const GrRect& devRect,
1088 const GrVec& devStrokeSize,
1089 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001090 const GrScalar& dx = devStrokeSize.fX;
1091 const GrScalar& dy = devStrokeSize.fY;
1092 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1093 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1094
bsalomon@google.com205d4602011-04-25 12:43:45 +00001095 GrScalar spare;
1096 {
1097 GrScalar w = devRect.width() - dx;
1098 GrScalar h = devRect.height() - dy;
1099 spare = GrMin(w, h);
1100 }
1101
1102 if (spare <= 0) {
1103 GrRect r(devRect);
1104 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001105 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001106 return;
1107 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001108 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001109 size_t vsize = GrDrawTarget::VertexSize(layout);
1110
1111 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001112 if (!geo.succeeded()) {
1113 GrPrintf("Failed to get space for vertices!\n");
1114 return;
1115 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001116 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1117 if (NULL == indexBuffer) {
1118 GrPrintf("Failed to create index buffer!\n");
1119 return;
1120 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001121
1122 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1123
1124 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1125 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1126 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1127 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1128
1129 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1130 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1131 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1132 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1133
1134 verts += sizeof(GrPoint);
1135 for (int i = 0; i < 4; ++i) {
1136 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1137 }
1138
bsalomon@google.coma3108262011-10-10 14:08:47 +00001139 GrColor innerColor;
1140 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001141 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001142 } else {
1143 innerColor = target->getColor();
1144 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001145 verts += 4 * vsize;
1146 for (int i = 0; i < 8; ++i) {
1147 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1148 }
1149
1150 verts += 8 * vsize;
1151 for (int i = 0; i < 8; ++i) {
1152 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1153 }
1154
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001155 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001156 target->drawIndexed(kTriangles_PrimitiveType,
1157 0, 0, 16, aaStrokeRectIndexCount());
1158}
1159
reed@google.com20efde72011-05-09 17:00:02 +00001160/**
1161 * Returns true if the rects edges are integer-aligned.
1162 */
1163static bool isIRect(const GrRect& r) {
1164 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1165 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1166}
1167
bsalomon@google.com205d4602011-04-25 12:43:45 +00001168static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001169 const GrRect& rect,
1170 GrScalar width,
1171 const GrMatrix* matrix,
1172 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001173 GrRect* devRect,
1174 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001175 // we use a simple alpha ramp to do aa on axis-aligned rects
1176 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001177 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001178
bsalomon@google.coma3108262011-10-10 14:08:47 +00001179 // we are keeping around the "tweak the alpha" trick because
1180 // it is our only hope for the fixed-pipe implementation.
1181 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001182 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001183 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001184 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001185 if (target->getCaps().fSupportPerVertexCoverage) {
1186 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001187#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001188 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001189#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001190 return false;
1191 } else {
1192 *useVertexCoverage = true;
1193 }
1194 } else {
1195 GrPrintf("Rect AA dropped because no support for coverage.\n");
1196 return false;
1197 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001198 }
1199
1200 if (target->getRenderTarget()->isMultisampled()) {
1201 return false;
1202 }
1203
bsalomon@google.com471d4712011-08-23 15:45:25 +00001204 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001205 return false;
1206 }
1207
1208 if (!target->getViewMatrix().preservesAxisAlignment()) {
1209 return false;
1210 }
1211
1212 if (NULL != matrix &&
1213 !matrix->preservesAxisAlignment()) {
1214 return false;
1215 }
1216
1217 *combinedMatrix = target->getViewMatrix();
1218 if (NULL != matrix) {
1219 combinedMatrix->preConcat(*matrix);
1220 GrAssert(combinedMatrix->preservesAxisAlignment());
1221 }
1222
1223 combinedMatrix->mapRect(devRect, rect);
1224 devRect->sort();
1225
1226 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001227 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001228 } else {
1229 return true;
1230 }
1231}
1232
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233void GrContext::drawRect(const GrPaint& paint,
1234 const GrRect& rect,
1235 GrScalar width,
1236 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001237 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001238
1239 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001240 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001241
bsalomon@google.com205d4602011-04-25 12:43:45 +00001242 GrRect devRect = rect;
1243 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001244 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001245 bool needAA = paint.fAntiAlias &&
1246 !this->getRenderTarget()->isMultisampled();
1247 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1248 &combinedMatrix, &devRect,
1249 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001250
1251 if (doAA) {
1252 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001253 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001254 GrMatrix inv;
1255 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001256 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001257 }
1258 }
1259 target->setViewMatrix(GrMatrix::I());
1260 if (width >= 0) {
1261 GrVec strokeSize;;
1262 if (width > 0) {
1263 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001264 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001265 strokeSize.setAbs(strokeSize);
1266 } else {
1267 strokeSize.set(GR_Scalar1, GR_Scalar1);
1268 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001269 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001270 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001271 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001272 }
1273 return;
1274 }
1275
bsalomon@google.com27847de2011-02-22 20:59:41 +00001276 if (width >= 0) {
1277 // TODO: consider making static vertex buffers for these cases.
1278 // Hairline could be done by just adding closing vertex to
1279 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001280 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1281
bsalomon@google.com27847de2011-02-22 20:59:41 +00001282 static const int worstCaseVertCount = 10;
1283 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1284
1285 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001286 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 return;
1288 }
1289
1290 GrPrimitiveType primType;
1291 int vertCount;
1292 GrPoint* vertex = geo.positions();
1293
1294 if (width > 0) {
1295 vertCount = 10;
1296 primType = kTriangleStrip_PrimitiveType;
1297 setStrokeRectStrip(vertex, rect, width);
1298 } else {
1299 // hairline
1300 vertCount = 5;
1301 primType = kLineStrip_PrimitiveType;
1302 vertex[0].set(rect.fLeft, rect.fTop);
1303 vertex[1].set(rect.fRight, rect.fTop);
1304 vertex[2].set(rect.fRight, rect.fBottom);
1305 vertex[3].set(rect.fLeft, rect.fBottom);
1306 vertex[4].set(rect.fLeft, rect.fTop);
1307 }
1308
1309 GrDrawTarget::AutoViewMatrixRestore avmr;
1310 if (NULL != matrix) {
1311 avmr.set(target);
1312 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001313 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314 }
1315
1316 target->drawNonIndexed(primType, 0, vertCount);
1317 } else {
1318 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001319 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001320 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1321 if (NULL == sqVB) {
1322 GrPrintf("Failed to create static rect vb.\n");
1323 return;
1324 }
1325 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1327 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001328 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001329 0, rect.height(), rect.fTop,
1330 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331
1332 if (NULL != matrix) {
1333 m.postConcat(*matrix);
1334 }
1335
1336 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001337 target->preConcatSamplerMatrices(stageMask, m);
1338
bsalomon@google.com27847de2011-02-22 20:59:41 +00001339 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1340 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001341 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001342 #endif
1343 }
1344}
1345
1346void GrContext::drawRectToRect(const GrPaint& paint,
1347 const GrRect& dstRect,
1348 const GrRect& srcRect,
1349 const GrMatrix* dstMatrix,
1350 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001351 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001352
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001353 // srcRect refers to paint's first texture
1354 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001355 drawRect(paint, dstRect, -1, dstMatrix);
1356 return;
1357 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001358
bsalomon@google.com27847de2011-02-22 20:59:41 +00001359 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1360
1361#if GR_STATIC_RECT_VB
1362 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001363
1364 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001365 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1366
1367 GrMatrix m;
1368
1369 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1370 0, dstRect.height(), dstRect.fTop,
1371 0, 0, GrMatrix::I()[8]);
1372 if (NULL != dstMatrix) {
1373 m.postConcat(*dstMatrix);
1374 }
1375 target->preConcatViewMatrix(m);
1376
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001377 // srcRect refers to first stage
1378 int otherStageMask = paint.getActiveStageMask() &
1379 (~(1 << GrPaint::kFirstTextureStage));
1380 if (otherStageMask) {
1381 target->preConcatSamplerMatrices(otherStageMask, m);
1382 }
1383
bsalomon@google.com27847de2011-02-22 20:59:41 +00001384 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1385 0, srcRect.height(), srcRect.fTop,
1386 0, 0, GrMatrix::I()[8]);
1387 if (NULL != srcMatrix) {
1388 m.postConcat(*srcMatrix);
1389 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001390 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001391
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001392 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1393 if (NULL == sqVB) {
1394 GrPrintf("Failed to create static rect vb.\n");
1395 return;
1396 }
1397 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1399#else
1400
1401 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001402#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001403 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001404#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1406#endif
1407
tomhudson@google.com93813632011-10-27 20:21:16 +00001408 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1409 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410 srcRects[0] = &srcRect;
1411 srcMatrices[0] = srcMatrix;
1412
1413 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1414#endif
1415}
1416
1417void GrContext::drawVertices(const GrPaint& paint,
1418 GrPrimitiveType primitiveType,
1419 int vertexCount,
1420 const GrPoint positions[],
1421 const GrPoint texCoords[],
1422 const GrColor colors[],
1423 const uint16_t indices[],
1424 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001425 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001426
1427 GrDrawTarget::AutoReleaseGeometry geo;
1428
1429 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1430
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001431 bool hasTexCoords[GrPaint::kTotalStages] = {
1432 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1433 0 // remaining stages use positions
1434 };
1435
1436 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001437
1438 if (NULL != colors) {
1439 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001440 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001441 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001442
1443 if (sizeof(GrPoint) != vertexSize) {
1444 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001445 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001446 return;
1447 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001448 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001449 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001450 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1451 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001452 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001453 NULL,
1454 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001455 void* curVertex = geo.vertices();
1456
1457 for (int i = 0; i < vertexCount; ++i) {
1458 *((GrPoint*)curVertex) = positions[i];
1459
1460 if (texOffsets[0] > 0) {
1461 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1462 }
1463 if (colorOffset > 0) {
1464 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1465 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001466 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001467 }
1468 } else {
1469 target->setVertexSourceToArray(layout, positions, vertexCount);
1470 }
1471
bsalomon@google.com91958362011-06-13 17:58:13 +00001472 // we don't currently apply offscreen AA to this path. Need improved
1473 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001474
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001475 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001476 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001477 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001478 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001479 target->drawNonIndexed(primitiveType, 0, vertexCount);
1480 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001481}
1482
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001483///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001484
reed@google.com07f3ee12011-05-16 17:21:57 +00001485void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1486 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001487
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001488 if (path.isEmpty()) {
1489#if GR_DEBUG
1490 GrPrintf("Empty path should have been caught by canvas.\n");
1491#endif
1492 if (GrIsFillInverted(fill)) {
1493 this->drawPaint(paint);
1494 }
1495 return;
1496 }
1497
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001499
bsalomon@google.com289533a2011-10-27 12:34:25 +00001500 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1501
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001502 // An Assumption here is that path renderer would use some form of tweaking
1503 // the src color (either the input alpha or in the frag shader) to implement
1504 // aa. If we have some future driver-mojo path AA that can do the right
1505 // thing WRT to the blend then we'll need some query on the PR.
1506 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001507#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001508 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001509#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001510 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001511 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001512
1513 bool doOSAA = false;
1514 GrPathRenderer* pr = NULL;
1515 if (prAA) {
1516 pr = this->getPathRenderer(path, fill, true);
1517 if (NULL == pr) {
1518 prAA = false;
1519 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1520 pr = this->getPathRenderer(path, fill, false);
1521 }
1522 } else {
1523 pr = this->getPathRenderer(path, fill, false);
1524 }
1525
bsalomon@google.com30085192011-08-19 15:42:31 +00001526 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001527#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001528 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001529#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001530 return;
1531 }
1532
bsalomon@google.com289533a2011-10-27 12:34:25 +00001533 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.comee435122011-07-01 14:57:55 +00001534 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001535
bsalomon@google.com289533a2011-10-27 12:34:25 +00001536 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001537 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001538
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001539 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001540 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1541 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001542 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001543 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001544 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001545 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001546 return;
1547 }
1548 }
reed@google.com70c136e2011-06-03 19:51:26 +00001549
reed@google.com07f3ee12011-05-16 17:21:57 +00001550 GrRect pathBounds = path.getBounds();
1551 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001552 if (NULL != translate) {
1553 pathBounds.offset(*translate);
1554 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001555 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001556 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001557 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001558 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001559 return;
1560 }
1561 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001562 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001563 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1564 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001565 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1566 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1567 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001568 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001569 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1570 }
1571 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001572 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001573 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001574 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1575 GrRect rect;
1576 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001577 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1578 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001579 target->drawSimpleRect(rect, NULL, stageMask);
1580 }
1581 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001582 rect.iset(clipIBounds.fLeft, bound.fTop,
1583 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001584 target->drawSimpleRect(rect, NULL, stageMask);
1585 }
1586 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001587 rect.iset(bound.fRight, bound.fTop,
1588 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001589 target->drawSimpleRect(rect, NULL, stageMask);
1590 }
1591 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001592 rect.iset(clipIBounds.fLeft, bound.fBottom,
1593 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001594 target->drawSimpleRect(rect, NULL, stageMask);
1595 }
1596 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001597 return;
1598 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001599 }
1600 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001601}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001602
bsalomon@google.com27847de2011-02-22 20:59:41 +00001603////////////////////////////////////////////////////////////////////////////////
1604
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001605bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001606 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001607}
1608
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001609void GrContext::flush(int flagsBitfield) {
1610 if (kDiscard_FlushBit & flagsBitfield) {
1611 fDrawBuffer->reset();
1612 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001613 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001614 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001615 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001616 fGpu->forceRenderTargetFlush();
1617 }
1618}
1619
1620void GrContext::flushText() {
1621 if (kText_DrawCategory == fLastDrawCategory) {
1622 flushDrawBuffer();
1623 }
1624}
1625
1626void GrContext::flushDrawBuffer() {
1627#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001628 if (fDrawBuffer) {
1629 fDrawBuffer->playback(fGpu);
1630 fDrawBuffer->reset();
1631 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001632#endif
1633}
1634
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001635bool GrContext::readTexturePixels(GrTexture* texture,
1636 int left, int top, int width, int height,
1637 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001638 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001639
1640 // TODO: code read pixels for textures that aren't rendertargets
1641
1642 this->flush();
1643 GrRenderTarget* target = texture->asRenderTarget();
1644 if (NULL != target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001645 return this->readRenderTargetPixels(target,
1646 left, top, width, height,
1647 config, buffer, 0);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001648 } else {
1649 return false;
1650 }
1651}
1652
1653bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
bsalomon@google.comc6980972011-11-02 19:57:21 +00001654 int left, int top, int width, int height,
1655 GrPixelConfig config, void* buffer,
1656 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001657 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001658 if (NULL == target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001659 target = fGpu->getRenderTarget();
1660 if (NULL == target) {
1661 return false;
1662 }
1663 }
1664
1665 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1666 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1667 // not supported at this time.
1668 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1669 !GrPixelConfigIsUnpremultiplied(config)) {
1670 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001671 }
1672
bsalomon@google.comc4364992011-11-07 15:54:49 +00001673 this->flush();
1674
1675 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001676 bool swapRAndB = NULL != src &&
1677 fGpu->preferredReadPixelsConfig(config) ==
1678 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001679
1680 bool flipY = NULL != src &&
1681 fGpu->readPixelsWillPayForYFlip(target, left, top,
1682 width, height, config,
1683 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001684 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1685 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001686
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001687 if (NULL == src && alphaConversion) {
1688 // we should fallback to cpu conversion here. This could happen when
1689 // we were given an external render target by the client that is not
1690 // also a texture (e.g. FBO 0 in GL)
1691 return false;
1692 }
1693
1694 // we draw to a scratch texture if any of these conversion are applied
1695 if (flipY || swapRAndB || alphaConversion) {
1696 GrAssert(NULL != src);
1697 if (swapRAndB) {
1698 config = GrPixelConfigSwapRAndB(config);
1699 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001700 }
1701 // Make the scratch a render target because we don't have a robust
1702 // readTexturePixels as of yet (it calls this function).
1703 const GrTextureDesc desc = {
1704 kRenderTarget_GrTextureFlagBit,
1705 kNone_GrAALevel,
1706 width, height,
1707 config
1708 };
1709 GrAutoScratchTexture ast(this, desc);
1710 GrTexture* texture = ast.texture();
1711 if (!texture) {
1712 return false;
1713 }
1714 target = texture->asRenderTarget();
1715 fGpu->setRenderTarget(target);
1716 GrAssert(NULL != target);
1717
1718 GrDrawTarget::AutoStateRestore asr(fGpu);
1719
1720 fGpu->setViewMatrix(GrMatrix::I());
1721 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
1722 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1723 fGpu->setAlpha(0xFF);
1724 fGpu->setBlendFunc(kOne_BlendCoeff,
1725 kZero_BlendCoeff);
1726
1727 GrSamplerState sampler;
1728 sampler.setClampNoFilter();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001729 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001730 GrMatrix matrix;
1731 if (flipY) {
1732 matrix.setTranslate(SK_Scalar1 * left,
1733 SK_Scalar1 * (top + height));
1734 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1735 } else {
1736 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1737 }
1738 matrix.postIDiv(src->width(), src->height());
1739 sampler.setMatrix(matrix);
1740 fGpu->setSamplerState(0, sampler);
1741 fGpu->setTexture(0, src);
1742 GrRect rect;
1743 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1744 fGpu->drawSimpleRect(rect, NULL, 0x1);
1745 left = 0;
1746 top = 0;
1747 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001748 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001749 left, top, width, height,
1750 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001751}
1752
1753void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001754 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001755 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001756 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001757
1758 // TODO: when underlying api has a direct way to do this we should use it
1759 // (e.g. glDrawPixels on desktop GL).
1760
bsalomon@google.comc4364992011-11-07 15:54:49 +00001761 this->flush(kForceCurrentRenderTarget_FlushBit);
bsalomon@google.com5c638652011-07-18 19:31:59 +00001762
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001763 const GrTextureDesc desc = {
1764 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001765 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001766 GrAutoScratchTexture ast(this, desc);
1767 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001768 if (NULL == texture) {
1769 return;
1770 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001771 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001772
bsalomon@google.com27847de2011-02-22 20:59:41 +00001773 GrDrawTarget::AutoStateRestore asr(fGpu);
1774
1775 GrMatrix matrix;
1776 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1777 fGpu->setViewMatrix(matrix);
1778
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001779 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001780 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1781 fGpu->setAlpha(0xFF);
1782 fGpu->setBlendFunc(kOne_BlendCoeff,
1783 kZero_BlendCoeff);
1784 fGpu->setTexture(0, texture);
1785
1786 GrSamplerState sampler;
1787 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001788 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001789 sampler.setMatrix(matrix);
1790 fGpu->setSamplerState(0, sampler);
1791
1792 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1793 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001794 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001795 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1796 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001797 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001798 return;
1799 }
1800 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1801 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1802}
1803////////////////////////////////////////////////////////////////////////////////
1804
1805void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001806
1807 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1808 int s = i + GrPaint::kFirstTextureStage;
1809 target->setTexture(s, paint.getTexture(i));
1810 target->setSamplerState(s, *paint.getTextureSampler(i));
1811 }
1812
1813 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1814
1815 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1816 int s = i + GrPaint::kFirstMaskStage;
1817 target->setTexture(s, paint.getMask(i));
1818 target->setSamplerState(s, *paint.getMaskSampler(i));
1819 }
1820
bsalomon@google.com27847de2011-02-22 20:59:41 +00001821 target->setColor(paint.fColor);
1822
1823 if (paint.fDither) {
1824 target->enableState(GrDrawTarget::kDither_StateBit);
1825 } else {
1826 target->disableState(GrDrawTarget::kDither_StateBit);
1827 }
1828 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001829 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001830 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001831 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001832 }
1833 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001834 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001835
1836 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1837 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1838 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001839}
1840
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001841GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001842 DrawCategory category) {
1843 if (category != fLastDrawCategory) {
1844 flushDrawBuffer();
1845 fLastDrawCategory = category;
1846 }
1847 SetPaint(paint, fGpu);
1848 GrDrawTarget* target = fGpu;
1849 switch (category) {
1850 case kText_DrawCategory:
1851#if DEFER_TEXT_RENDERING
1852 target = fDrawBuffer;
1853 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1854#else
1855 target = fGpu;
1856#endif
1857 break;
1858 case kUnbuffered_DrawCategory:
1859 target = fGpu;
1860 break;
1861 case kBuffered_DrawCategory:
1862 target = fDrawBuffer;
1863 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1864 break;
1865 }
1866 return target;
1867}
1868
bsalomon@google.com289533a2011-10-27 12:34:25 +00001869GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1870 GrPathFill fill,
1871 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001872 if (NULL == fPathRendererChain) {
1873 fPathRendererChain =
1874 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1875 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001876 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1877 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001878}
1879
bsalomon@google.com27847de2011-02-22 20:59:41 +00001880////////////////////////////////////////////////////////////////////////////////
1881
bsalomon@google.com27847de2011-02-22 20:59:41 +00001882void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001883 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001884 fGpu->setRenderTarget(target);
1885}
1886
1887GrRenderTarget* GrContext::getRenderTarget() {
1888 return fGpu->getRenderTarget();
1889}
1890
1891const GrRenderTarget* GrContext::getRenderTarget() const {
1892 return fGpu->getRenderTarget();
1893}
1894
1895const GrMatrix& GrContext::getMatrix() const {
1896 return fGpu->getViewMatrix();
1897}
1898
1899void GrContext::setMatrix(const GrMatrix& m) {
1900 fGpu->setViewMatrix(m);
1901}
1902
1903void GrContext::concatMatrix(const GrMatrix& m) const {
1904 fGpu->preConcatViewMatrix(m);
1905}
1906
1907static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1908 intptr_t mask = 1 << shift;
1909 if (pred) {
1910 bits |= mask;
1911 } else {
1912 bits &= ~mask;
1913 }
1914 return bits;
1915}
1916
1917void GrContext::resetStats() {
1918 fGpu->resetStats();
1919}
1920
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001921const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001922 return fGpu->getStats();
1923}
1924
1925void GrContext::printStats() const {
1926 fGpu->printStats();
1927}
1928
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001929GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001930 fGpu = gpu;
1931 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001932 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001933
bsalomon@google.com30085192011-08-19 15:42:31 +00001934 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001935
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001936 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1937 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938 fFontCache = new GrFontCache(fGpu);
1939
1940 fLastDrawCategory = kUnbuffered_DrawCategory;
1941
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001942 fDrawBuffer = NULL;
1943 fDrawBufferVBAllocPool = NULL;
1944 fDrawBufferIBAllocPool = NULL;
1945
bsalomon@google.com205d4602011-04-25 12:43:45 +00001946 fAAFillRectIndexBuffer = NULL;
1947 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001948
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001949 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1950 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001951 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1952 }
1953 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001954
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001955 this->setupDrawBuffer();
1956}
1957
1958void GrContext::setupDrawBuffer() {
1959
1960 GrAssert(NULL == fDrawBuffer);
1961 GrAssert(NULL == fDrawBufferVBAllocPool);
1962 GrAssert(NULL == fDrawBufferIBAllocPool);
1963
bsalomon@google.com27847de2011-02-22 20:59:41 +00001964#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001965 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001966 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001967 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1968 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001969 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001970 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001971 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001972 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1973
bsalomon@google.com471d4712011-08-23 15:45:25 +00001974 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1975 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001976 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001977#endif
1978
1979#if BATCH_RECT_TO_RECT
1980 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1981#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982}
1983
bsalomon@google.com27847de2011-02-22 20:59:41 +00001984GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1985 GrDrawTarget* target;
1986#if DEFER_TEXT_RENDERING
1987 target = prepareToDraw(paint, kText_DrawCategory);
1988#else
1989 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1990#endif
1991 SetPaint(paint, target);
1992 return target;
1993}
1994
1995const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1996 return fGpu->getQuadIndexBuffer();
1997}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001998
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001999void GrContext::convolveInX(GrTexture* texture,
2000 const SkRect& rect,
2001 const float* kernel,
2002 int kernelWidth) {
2003 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
2004 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2005}
2006
2007void GrContext::convolveInY(GrTexture* texture,
2008 const SkRect& rect,
2009 const float* kernel,
2010 int kernelWidth) {
2011 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
2012 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2013}
2014
2015void GrContext::convolve(GrTexture* texture,
2016 const SkRect& rect,
2017 float imageIncrement[2],
2018 const float* kernel,
2019 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002020 GrDrawTarget::AutoStateRestore asr(fGpu);
2021 GrMatrix sampleM;
2022 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
2023 GrSamplerState::kClamp_WrapMode,
2024 GrSamplerState::kConvolution_Filter);
2025 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002026 sampleM.setScale(GR_Scalar1 / texture->width(),
2027 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002028 sampler.setMatrix(sampleM);
2029 fGpu->setSamplerState(0, sampler);
2030 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002031 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002032 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002033 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2034}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002035
2036///////////////////////////////////////////////////////////////////////////////