blob: 8c06c214e4155d532d7be7490567d7bcdc7687fa [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();
1676
1677 bool flipY = NULL != src &&
1678 fGpu->readPixelsWillPayForYFlip(target, left, top,
1679 width, height, config,
1680 rowBytes);
1681
1682 if (flipY || (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1683 GrPixelConfigIsUnpremultiplied(config))) {
1684 if (!src) {
1685 // we should fallback to cpu conversion here. This could happen when
1686 // we were given an external render target by the client that is not
1687 // also a texture (e.g. FBO 0 in GL)
1688 return false;
1689 }
1690 // Make the scratch a render target because we don't have a robust
1691 // readTexturePixels as of yet (it calls this function).
1692 const GrTextureDesc desc = {
1693 kRenderTarget_GrTextureFlagBit,
1694 kNone_GrAALevel,
1695 width, height,
1696 config
1697 };
1698 GrAutoScratchTexture ast(this, desc);
1699 GrTexture* texture = ast.texture();
1700 if (!texture) {
1701 return false;
1702 }
1703 target = texture->asRenderTarget();
1704 fGpu->setRenderTarget(target);
1705 GrAssert(NULL != target);
1706
1707 GrDrawTarget::AutoStateRestore asr(fGpu);
1708
1709 fGpu->setViewMatrix(GrMatrix::I());
1710 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
1711 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1712 fGpu->setAlpha(0xFF);
1713 fGpu->setBlendFunc(kOne_BlendCoeff,
1714 kZero_BlendCoeff);
1715
1716 GrSamplerState sampler;
1717 sampler.setClampNoFilter();
1718 GrMatrix matrix;
1719 if (flipY) {
1720 matrix.setTranslate(SK_Scalar1 * left,
1721 SK_Scalar1 * (top + height));
1722 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1723 } else {
1724 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1725 }
1726 matrix.postIDiv(src->width(), src->height());
1727 sampler.setMatrix(matrix);
1728 fGpu->setSamplerState(0, sampler);
1729 fGpu->setTexture(0, src);
1730 GrRect rect;
1731 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1732 fGpu->drawSimpleRect(rect, NULL, 0x1);
1733 left = 0;
1734 top = 0;
1735 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001736 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001737 left, top, width, height,
1738 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001739}
1740
1741void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001742 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001743 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001744 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001745
1746 // TODO: when underlying api has a direct way to do this we should use it
1747 // (e.g. glDrawPixels on desktop GL).
1748
bsalomon@google.comc4364992011-11-07 15:54:49 +00001749 this->flush(kForceCurrentRenderTarget_FlushBit);
bsalomon@google.com5c638652011-07-18 19:31:59 +00001750
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001751 const GrTextureDesc desc = {
1752 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001753 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001754 GrAutoScratchTexture ast(this, desc);
1755 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001756 if (NULL == texture) {
1757 return;
1758 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001759 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001760
bsalomon@google.com27847de2011-02-22 20:59:41 +00001761 GrDrawTarget::AutoStateRestore asr(fGpu);
1762
1763 GrMatrix matrix;
1764 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1765 fGpu->setViewMatrix(matrix);
1766
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001767 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001768 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1769 fGpu->setAlpha(0xFF);
1770 fGpu->setBlendFunc(kOne_BlendCoeff,
1771 kZero_BlendCoeff);
1772 fGpu->setTexture(0, texture);
1773
1774 GrSamplerState sampler;
1775 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001776 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001777 sampler.setMatrix(matrix);
1778 fGpu->setSamplerState(0, sampler);
1779
1780 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1781 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001782 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001783 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1784 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001785 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001786 return;
1787 }
1788 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1789 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1790}
1791////////////////////////////////////////////////////////////////////////////////
1792
1793void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001794
1795 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1796 int s = i + GrPaint::kFirstTextureStage;
1797 target->setTexture(s, paint.getTexture(i));
1798 target->setSamplerState(s, *paint.getTextureSampler(i));
1799 }
1800
1801 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1802
1803 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1804 int s = i + GrPaint::kFirstMaskStage;
1805 target->setTexture(s, paint.getMask(i));
1806 target->setSamplerState(s, *paint.getMaskSampler(i));
1807 }
1808
bsalomon@google.com27847de2011-02-22 20:59:41 +00001809 target->setColor(paint.fColor);
1810
1811 if (paint.fDither) {
1812 target->enableState(GrDrawTarget::kDither_StateBit);
1813 } else {
1814 target->disableState(GrDrawTarget::kDither_StateBit);
1815 }
1816 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001817 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001818 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001819 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001820 }
1821 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001822 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001823
1824 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1825 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1826 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001827}
1828
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001829GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001830 DrawCategory category) {
1831 if (category != fLastDrawCategory) {
1832 flushDrawBuffer();
1833 fLastDrawCategory = category;
1834 }
1835 SetPaint(paint, fGpu);
1836 GrDrawTarget* target = fGpu;
1837 switch (category) {
1838 case kText_DrawCategory:
1839#if DEFER_TEXT_RENDERING
1840 target = fDrawBuffer;
1841 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1842#else
1843 target = fGpu;
1844#endif
1845 break;
1846 case kUnbuffered_DrawCategory:
1847 target = fGpu;
1848 break;
1849 case kBuffered_DrawCategory:
1850 target = fDrawBuffer;
1851 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1852 break;
1853 }
1854 return target;
1855}
1856
bsalomon@google.com289533a2011-10-27 12:34:25 +00001857GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1858 GrPathFill fill,
1859 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001860 if (NULL == fPathRendererChain) {
1861 fPathRendererChain =
1862 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1863 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001864 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1865 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001866}
1867
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868////////////////////////////////////////////////////////////////////////////////
1869
bsalomon@google.com27847de2011-02-22 20:59:41 +00001870void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001871 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001872 fGpu->setRenderTarget(target);
1873}
1874
1875GrRenderTarget* GrContext::getRenderTarget() {
1876 return fGpu->getRenderTarget();
1877}
1878
1879const GrRenderTarget* GrContext::getRenderTarget() const {
1880 return fGpu->getRenderTarget();
1881}
1882
1883const GrMatrix& GrContext::getMatrix() const {
1884 return fGpu->getViewMatrix();
1885}
1886
1887void GrContext::setMatrix(const GrMatrix& m) {
1888 fGpu->setViewMatrix(m);
1889}
1890
1891void GrContext::concatMatrix(const GrMatrix& m) const {
1892 fGpu->preConcatViewMatrix(m);
1893}
1894
1895static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1896 intptr_t mask = 1 << shift;
1897 if (pred) {
1898 bits |= mask;
1899 } else {
1900 bits &= ~mask;
1901 }
1902 return bits;
1903}
1904
1905void GrContext::resetStats() {
1906 fGpu->resetStats();
1907}
1908
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001909const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001910 return fGpu->getStats();
1911}
1912
1913void GrContext::printStats() const {
1914 fGpu->printStats();
1915}
1916
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001917GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001918 fGpu = gpu;
1919 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001920 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001921
bsalomon@google.com30085192011-08-19 15:42:31 +00001922 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001923
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001924 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1925 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001926 fFontCache = new GrFontCache(fGpu);
1927
1928 fLastDrawCategory = kUnbuffered_DrawCategory;
1929
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001930 fDrawBuffer = NULL;
1931 fDrawBufferVBAllocPool = NULL;
1932 fDrawBufferIBAllocPool = NULL;
1933
bsalomon@google.com205d4602011-04-25 12:43:45 +00001934 fAAFillRectIndexBuffer = NULL;
1935 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001936
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001937 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1938 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001939 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1940 }
1941 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001942
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001943 this->setupDrawBuffer();
1944}
1945
1946void GrContext::setupDrawBuffer() {
1947
1948 GrAssert(NULL == fDrawBuffer);
1949 GrAssert(NULL == fDrawBufferVBAllocPool);
1950 GrAssert(NULL == fDrawBufferIBAllocPool);
1951
bsalomon@google.com27847de2011-02-22 20:59:41 +00001952#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001953 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001954 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001955 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1956 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001957 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001958 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001959 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001960 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1961
bsalomon@google.com471d4712011-08-23 15:45:25 +00001962 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1963 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001964 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001965#endif
1966
1967#if BATCH_RECT_TO_RECT
1968 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1969#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001970}
1971
bsalomon@google.com27847de2011-02-22 20:59:41 +00001972GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1973 GrDrawTarget* target;
1974#if DEFER_TEXT_RENDERING
1975 target = prepareToDraw(paint, kText_DrawCategory);
1976#else
1977 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1978#endif
1979 SetPaint(paint, target);
1980 return target;
1981}
1982
1983const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1984 return fGpu->getQuadIndexBuffer();
1985}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001986
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001987void GrContext::convolveInX(GrTexture* texture,
1988 const SkRect& rect,
1989 const float* kernel,
1990 int kernelWidth) {
1991 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1992 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1993}
1994
1995void GrContext::convolveInY(GrTexture* texture,
1996 const SkRect& rect,
1997 const float* kernel,
1998 int kernelWidth) {
1999 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
2000 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2001}
2002
2003void GrContext::convolve(GrTexture* texture,
2004 const SkRect& rect,
2005 float imageIncrement[2],
2006 const float* kernel,
2007 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002008 GrDrawTarget::AutoStateRestore asr(fGpu);
2009 GrMatrix sampleM;
2010 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
2011 GrSamplerState::kClamp_WrapMode,
2012 GrSamplerState::kConvolution_Filter);
2013 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002014 sampleM.setScale(GR_Scalar1 / texture->width(),
2015 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002016 sampler.setMatrix(sampleM);
2017 fGpu->setSamplerState(0, sampler);
2018 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002019 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002020 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002021 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2022}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002023
2024///////////////////////////////////////////////////////////////////////////////