blob: 3f5ab5471beb0c086568cf2fcaedb77b4e63eb55 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000021#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000022#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023
bsalomon@google.com91958362011-06-13 17:58:13 +000024// Using MSAA seems to be slower for some yet unknown reason.
25#define PREFER_MSAA_OFFSCREEN_AA 0
26#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000027
bsalomon@google.com27847de2011-02-22 20:59:41 +000028#define DEFER_TEXT_RENDERING 1
29
30#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
bsalomon@google.comd46e2422011-09-23 17:40:07 +000032// When we're using coverage AA but the blend is incompatible (given gpu
33// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000034#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000035
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000036static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
37static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000038
39static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
40static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
41
42// We are currently only batching Text and drawRectToRect, both
43// of which use the quad index buffer.
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
46
bsalomon@google.com05ef5102011-05-02 21:14:59 +000047GrContext* GrContext::Create(GrEngine engine,
48 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000049 GrContext* ctx = NULL;
50 GrGpu* fGpu = GrGpu::Create(engine, context3D);
51 if (NULL != fGpu) {
52 ctx = new GrContext(fGpu);
53 fGpu->unref();
54 }
55 return ctx;
56}
57
58GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000059 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000060}
61
62GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000063 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000064 delete fTextureCache;
65 delete fFontCache;
66 delete fDrawBuffer;
67 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000068 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000069
bsalomon@google.com205d4602011-04-25 12:43:45 +000070 GrSafeUnref(fAAFillRectIndexBuffer);
71 GrSafeUnref(fAAStrokeRectIndexBuffer);
72 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000073 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com30085192011-08-19 15:42:31 +000086 // a path renderer may be holding onto resources that
87 // are now unusable
88 GrSafeSetNull(fPathRendererChain);
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 delete fDrawBuffer;
91 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000092
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 delete fDrawBufferVBAllocPool;
94 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000095
bsalomon@google.com8fe72472011-03-30 21:26:44 +000096 delete fDrawBufferIBAllocPool;
97 fDrawBufferIBAllocPool = NULL;
98
bsalomon@google.com205d4602011-04-25 12:43:45 +000099 GrSafeSetNull(fAAFillRectIndexBuffer);
100 GrSafeSetNull(fAAStrokeRectIndexBuffer);
101
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102 fTextureCache->removeAll();
103 fFontCache->freeAll();
104 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000105}
106
107void GrContext::resetContext() {
108 fGpu->markContextDirty();
109}
110
111void GrContext::freeGpuResources() {
112 this->flush();
113 fTextureCache->removeAll();
114 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000115 // a path renderer may be holding onto resources
116 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000117}
118
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000119////////////////////////////////////////////////////////////////////////////////
120
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000121int GrContext::PaintStageVertexLayoutBits(
122 const GrPaint& paint,
123 const bool hasTexCoords[GrPaint::kTotalStages]) {
124 int stageMask = paint.getActiveStageMask();
125 int layout = 0;
126 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
127 if ((1 << i) & stageMask) {
128 if (NULL != hasTexCoords && hasTexCoords[i]) {
129 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
130 } else {
131 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
132 }
133 }
134 }
135 return layout;
136}
137
138
139////////////////////////////////////////////////////////////////////////////////
140
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000141enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000142 // flags for textures
143 kNPOTBit = 0x1,
144 kFilterBit = 0x2,
145 kScratchBit = 0x4,
146
147 // resource type
148 kTextureBit = 0x8,
149 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000150};
151
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000152GrTexture* GrContext::TextureCacheEntry::texture() const {
153 if (NULL == fEntry) {
154 return NULL;
155 } else {
156 return (GrTexture*) fEntry->resource();
157 }
158}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000159
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000160namespace {
161// returns true if this is a "special" texture because of gpu NPOT limitations
162bool gen_texture_key_values(const GrGpu* gpu,
163 const GrSamplerState& sampler,
164 GrContext::TextureKey clientKey,
165 int width,
166 int height,
167 bool scratch,
168 uint32_t v[4]) {
169 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
170 // we assume we only need 16 bits of width and height
171 // assert that texture creation will fail anyway if this assumption
172 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000173 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000174 v[0] = clientKey & 0xffffffffUL;
175 v[1] = (clientKey >> 32) & 0xffffffffUL;
176 v[2] = width | (height << 16);
177
178 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000179 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000180 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
181
182 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
183 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
184
185 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000187 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 }
190 }
191 }
192
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 if (scratch) {
194 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197 v[3] |= kTextureBit;
198
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199 return v[3] & kNPOTBit;
200}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000201
202// we should never have more than one stencil buffer with same combo of
203// (width,height,samplecount)
204void gen_stencil_key_values(int width, int height,
205 int sampleCnt, uint32_t v[4]) {
206 v[0] = width;
207 v[1] = height;
208 v[2] = sampleCnt;
209 v[3] = kStencilBufferBit;
210}
211
212void gen_stencil_key_values(const GrStencilBuffer* sb,
213 uint32_t v[4]) {
214 gen_stencil_key_values(sb->width(), sb->height(),
215 sb->numSamples(), v);
216}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000217}
218
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000219GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
220 int width,
221 int height,
222 const GrSamplerState& sampler) {
223 uint32_t v[4];
224 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
225 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000226 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
227 GrResourceCache::kNested_LockType));
228}
229
230GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
231 uint32_t v[4];
232 gen_stencil_key_values(sb, v);
233 GrResourceKey resourceKey(v);
234 return fTextureCache->createAndLock(resourceKey, sb);
235}
236
237GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
238 int sampleCnt) {
239 uint32_t v[4];
240 gen_stencil_key_values(width, height, sampleCnt, v);
241 GrResourceKey resourceKey(v);
242 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
243 GrResourceCache::kSingle_LockType);
244 if (NULL != entry) {
245 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
246 return sb;
247 } else {
248 return NULL;
249 }
250}
251
252void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
253 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000254}
255
256static void stretchImage(void* dst,
257 int dstW,
258 int dstH,
259 void* src,
260 int srcW,
261 int srcH,
262 int bpp) {
263 GrFixed dx = (srcW << 16) / dstW;
264 GrFixed dy = (srcH << 16) / dstH;
265
266 GrFixed y = dy >> 1;
267
268 int dstXLimit = dstW*bpp;
269 for (int j = 0; j < dstH; ++j) {
270 GrFixed x = dx >> 1;
271 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
272 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
273 for (int i = 0; i < dstXLimit; i += bpp) {
274 memcpy((uint8_t*) dstRow + i,
275 (uint8_t*) srcRow + (x>>16)*bpp,
276 bpp);
277 x += dx;
278 }
279 y += dy;
280 }
281}
282
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000283GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000284 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000285 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000286 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000287 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000288
289#if GR_DUMP_TEXTURE_UPLOAD
290 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
291#endif
292
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000293 TextureCacheEntry entry;
294 uint32_t v[4];
295 bool special = gen_texture_key_values(fGpu, sampler, key,
296 desc.fWidth, desc.fHeight, false, v);
297 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000298
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000299 if (special) {
300 TextureCacheEntry clampEntry =
301 findAndLockTexture(key, desc.fWidth, desc.fHeight,
302 GrSamplerState::ClampNoFilter());
303
304 if (NULL == clampEntry.texture()) {
305 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000306 GrSamplerState::ClampNoFilter(),
307 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000308 GrAssert(NULL != clampEntry.texture());
309 if (NULL == clampEntry.texture()) {
310 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000311 }
312 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000313 GrTextureDesc rtDesc = desc;
314 rtDesc.fFlags = rtDesc.fFlags |
315 kRenderTarget_GrTextureFlagBit |
316 kNoStencil_GrTextureFlagBit;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000317 rtDesc.fWidth =
318 GrNextPow2(GrMax<int>(desc.fWidth,
319 fGpu->getCaps().fMinRenderTargetWidth));
320 rtDesc.fHeight =
321 GrNextPow2(GrMax<int>(desc.fHeight,
322 fGpu->getCaps().fMinRenderTargetHeight));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000323
324 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
325
326 if (NULL != texture) {
327 GrDrawTarget::AutoStateRestore asr(fGpu);
328 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000329 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000330 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000331 fGpu->setViewMatrix(GrMatrix::I());
332 fGpu->setAlpha(0xff);
333 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
334 fGpu->disableState(GrDrawTarget::kDither_StateBit |
335 GrDrawTarget::kClip_StateBit |
336 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000337 GrSamplerState::Filter filter;
338 // if filtering is not desired then we want to ensure all
339 // texels in the resampled image are copies of texels from
340 // the original.
341 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
342 filter = GrSamplerState::kNearest_Filter;
343 } else {
344 filter = GrSamplerState::kBilinear_Filter;
345 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000346 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
347 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000348 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000349 fGpu->setSamplerState(0, stretchSampler);
350
351 static const GrVertexLayout layout =
352 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
353 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
354
355 if (arg.succeeded()) {
356 GrPoint* verts = (GrPoint*) arg.vertices();
357 verts[0].setIRectFan(0, 0,
358 texture->width(),
359 texture->height(),
360 2*sizeof(GrPoint));
361 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
362 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
363 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000364 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000365 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000366 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000367 } else {
368 // TODO: Our CPU stretch doesn't filter. But we create separate
369 // stretched textures when the sampler state is either filtered or
370 // not. Either implement filtered stretch blit on CPU or just create
371 // one when FBO case fails.
372
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000373 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000374 // no longer need to clamp at min RT size.
375 rtDesc.fWidth = GrNextPow2(desc.fWidth);
376 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000377 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000378 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000379 rtDesc.fWidth *
380 rtDesc.fHeight);
381 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
382 srcData, desc.fWidth, desc.fHeight, bpp);
383
384 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
385
386 GrTexture* texture = fGpu->createTexture(rtDesc,
387 stretchedPixels.get(),
388 stretchedRowBytes);
389 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000390 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000392 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000393
394 } else {
395 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
396 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000397 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 }
399 }
400 return entry;
401}
402
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403namespace {
404inline void gen_scratch_tex_key_values(const GrGpu* gpu,
405 const GrTextureDesc& desc,
406 uint32_t v[4]) {
407 // Instead of a client-provided key of the texture contents
408 // we create a key of from the descriptor.
409 GrContext::TextureKey descKey = desc.fAALevel |
410 (desc.fFlags << 8) |
411 ((uint64_t) desc.fFormat << 32);
412 // this code path isn't friendly to tiling with NPOT restricitons
413 // We just pass ClampNoFilter()
414 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
415 desc.fWidth, desc.fHeight, true, v);
416}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000417}
418
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000419GrContext::TextureCacheEntry GrContext::lockScratchTexture(
420 const GrTextureDesc& inDesc,
421 ScratchTexMatch match) {
422
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000423 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000424 if (kExact_ScratchTexMatch != match) {
425 // bin by pow2 with a reasonable min
426 static const int MIN_SIZE = 256;
427 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
428 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
429 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000430
431 uint32_t p0 = desc.fFormat;
432 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
433
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000435 int origWidth = desc.fWidth;
436 int origHeight = desc.fHeight;
437 bool doubledW = false;
438 bool doubledH = false;
439
440 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441 uint32_t v[4];
442 gen_scratch_tex_key_values(fGpu, desc, v);
443 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000444 entry = fTextureCache->findAndLock(key,
445 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000446 // if we miss, relax the fit of the flags...
447 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000448 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000449 break;
450 }
451 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
452 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
453 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
454 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
455 } else if (!doubledW) {
456 desc.fFlags = inDesc.fFlags;
457 desc.fWidth *= 2;
458 doubledW = true;
459 } else if (!doubledH) {
460 desc.fFlags = inDesc.fFlags;
461 desc.fWidth = origWidth;
462 desc.fHeight *= 2;
463 doubledH = true;
464 } else {
465 break;
466 }
467
468 } while (true);
469
470 if (NULL == entry) {
471 desc.fFlags = inDesc.fFlags;
472 desc.fWidth = origWidth;
473 desc.fHeight = origHeight;
474 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
475 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000476 uint32_t v[4];
477 gen_scratch_tex_key_values(fGpu, desc, v);
478 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000479 entry = fTextureCache->createAndLock(key, texture);
480 }
481 }
482
483 // If the caller gives us the same desc/sampler twice we don't want
484 // to return the same texture the second time (unless it was previously
485 // released). So we detach the entry from the cache and reattach at release.
486 if (NULL != entry) {
487 fTextureCache->detach(entry);
488 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000489 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000490}
491
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000492void GrContext::unlockTexture(TextureCacheEntry entry) {
493 // If this is a scratch texture we detached it from the cache
494 // while it was locked (to avoid two callers simultaneously getting
495 // the same texture).
496 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
497 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000498 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000499 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000500 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000501}
502
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000503GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000504 void* srcData,
505 size_t rowBytes) {
506 return fGpu->createTexture(desc, srcData, rowBytes);
507}
508
509void GrContext::getTextureCacheLimits(int* maxTextures,
510 size_t* maxTextureBytes) const {
511 fTextureCache->getLimits(maxTextures, maxTextureBytes);
512}
513
514void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
515 fTextureCache->setLimits(maxTextures, maxTextureBytes);
516}
517
bsalomon@google.com91958362011-06-13 17:58:13 +0000518int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000519 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000520}
521
522int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000523 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000524}
525
526///////////////////////////////////////////////////////////////////////////////
527
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000528GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
529 // validate flags here so that GrGpu subclasses don't have to check
530 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
531 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000532 return NULL;
533 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000534 if (desc.fSampleCnt &&
535 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000536 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000537 }
538 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
539 desc.fSampleCnt &&
540 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
541 return NULL;
542 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000543 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000544}
545
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000546///////////////////////////////////////////////////////////////////////////////
547
bsalomon@google.com27847de2011-02-22 20:59:41 +0000548bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000549 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000550 const GrDrawTarget::Caps& caps = fGpu->getCaps();
551 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000552 return false;
553 }
554
bsalomon@google.com27847de2011-02-22 20:59:41 +0000555 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
556
557 if (!isPow2) {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000558 if (!caps.fNPOTTextureSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000559 return false;
560 }
561
562 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
563 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000564 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000565 return false;
566 }
567 }
568 return true;
569}
570
571////////////////////////////////////////////////////////////////////////////////
572
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000573const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
574
bsalomon@google.com27847de2011-02-22 20:59:41 +0000575void GrContext::setClip(const GrClip& clip) {
576 fGpu->setClip(clip);
577 fGpu->enableState(GrDrawTarget::kClip_StateBit);
578}
579
580void GrContext::setClip(const GrIRect& rect) {
581 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000582 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000583 fGpu->setClip(clip);
584}
585
586////////////////////////////////////////////////////////////////////////////////
587
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000588void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000589 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000590 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000591}
592
593void GrContext::drawPaint(const GrPaint& paint) {
594 // set rect to be big enough to fill the space, but not super-huge, so we
595 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000596 GrRect r;
597 r.setLTRB(0, 0,
598 GrIntToScalar(getRenderTarget()->width()),
599 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000600 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000601 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000602 SkTLazy<GrPaint> tmpPaint;
603 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000604 // We attempt to map r by the inverse matrix and draw that. mapRect will
605 // map the four corners and bound them with a new rect. This will not
606 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000607 if (!this->getMatrix().hasPerspective()) {
608 if (!fGpu->getViewInverse(&inverse)) {
609 GrPrintf("Could not invert matrix");
610 return;
611 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000612 inverse.mapRect(&r);
613 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000614 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
615 if (!fGpu->getViewInverse(&inverse)) {
616 GrPrintf("Could not invert matrix");
617 return;
618 }
619 tmpPaint.set(paint);
620 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
621 p = tmpPaint.get();
622 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000623 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000624 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000625 // by definition this fills the entire clip, no need for AA
626 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000627 if (!tmpPaint.isValid()) {
628 tmpPaint.set(paint);
629 p = tmpPaint.get();
630 }
631 GrAssert(p == tmpPaint.get());
632 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000633 }
634 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000635}
636
bsalomon@google.com205d4602011-04-25 12:43:45 +0000637////////////////////////////////////////////////////////////////////////////////
638
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000639namespace {
640inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
641 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
642}
643}
644
bsalomon@google.com91958362011-06-13 17:58:13 +0000645struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000646 enum Downsample {
647 k4x4TwoPass_Downsample,
648 k4x4SinglePass_Downsample,
649 kFSAA_Downsample
650 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000651 int fTileSizeX;
652 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000653 int fTileCountX;
654 int fTileCountY;
655 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000656 GrAutoScratchTexture fOffscreen0;
657 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000658 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000659 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000660};
661
bsalomon@google.com471d4712011-08-23 15:45:25 +0000662bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000663 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000664#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000665 return false;
666#else
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000667 if (!target->isAntialiasState()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000668 return false;
669 }
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000670 // Line primitves are always rasterized as 1 pixel wide.
671 // Super-sampling would make them too thin but MSAA would be OK.
672 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000673 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000674 return false;
675 }
676 if (target->getRenderTarget()->isMultisampled()) {
677 return false;
678 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000679 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000680 GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000681 return false;
682 }
683 return true;
684#endif
685}
686
bsalomon@google.com91958362011-06-13 17:58:13 +0000687bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000688 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000689 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000690 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000691 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000692
693 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000694
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000695 GrAssert(NULL == record->fOffscreen0.texture());
696 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000697 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000698
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000699 int boundW = boundRect.width();
700 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000701
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000702 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000703
704 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
705 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
706
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000707 if (requireStencil) {
708 desc.fFlags = kRenderTarget_GrTextureFlagBit;
709 } else {
710 desc.fFlags = kRenderTarget_GrTextureFlagBit |
711 kNoStencil_GrTextureFlagBit;
712 }
713
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000714 desc.fFormat = kRGBA_8888_GrPixelConfig;
715
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000716 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000717 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000718 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000719 desc.fAALevel = kMed_GrAALevel;
720 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000721 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000722 OffscreenRecord::k4x4SinglePass_Downsample :
723 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000724 record->fScale = OFFSCREEN_SSAA_SCALE;
725 // both downsample paths assume this
726 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000727 desc.fAALevel = kNone_GrAALevel;
728 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000729
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000730 desc.fWidth *= record->fScale;
731 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000732 record->fOffscreen0.set(this, desc);
733 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000734 return false;
735 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000736 // the approximate lookup might have given us some slop space, might as well
737 // use it when computing the tiles size.
738 // these are scale values, will adjust after considering
739 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000740 record->fTileSizeX = record->fOffscreen0.texture()->width();
741 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000742
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000743 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000744 desc.fWidth /= 2;
745 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000746 record->fOffscreen1.set(this, desc);
747 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000748 return false;
749 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000750 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000751 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000752 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000753 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000754 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000755 record->fTileSizeX /= record->fScale;
756 record->fTileSizeY /= record->fScale;
757
758 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
759 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
760
tomhudson@google.com237a4612011-07-19 15:44:00 +0000761 record->fClip = target->getClip();
762
bsalomon@google.com91958362011-06-13 17:58:13 +0000763 target->saveCurrentDrawState(&record->fSavedState);
764 return true;
765}
766
767void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
768 const GrIRect& boundRect,
769 int tileX, int tileY,
770 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000771
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000772 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000773 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000774
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000775 GrPaint tempPaint;
776 tempPaint.reset();
777 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000778 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000779
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000780 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000781 int left = boundRect.fLeft + tileX * record->fTileSizeX;
782 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000783 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000784 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000785 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000786 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000787 target->postConcatViewMatrix(scaleM);
788
bsalomon@google.com91958362011-06-13 17:58:13 +0000789 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000790 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000791 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000792 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000793 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
794 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000795 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000796#if 0
797 // visualize tile boundaries by setting edges of offscreen to white
798 // and interior to tranparent. black.
799 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000800
bsalomon@google.com91958362011-06-13 17:58:13 +0000801 static const int gOffset = 2;
802 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
803 record->fScale * w - gOffset,
804 record->fScale * h - gOffset);
805 target->clear(&clear2, 0x0);
806#else
807 target->clear(&clear, 0x0);
808#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000809}
810
bsalomon@google.com91958362011-06-13 17:58:13 +0000811void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000812 const GrPaint& paint,
813 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000814 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000815 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000816 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000817 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000818 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000819 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000820 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
821 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000822 tileRect.fRight = (tileX == record->fTileCountX-1) ?
823 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000824 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000825 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
826 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000827 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000828
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000829 GrSamplerState::Filter filter;
830 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
831 filter = GrSamplerState::k4x4Downsample_Filter;
832 } else {
833 filter = GrSamplerState::kBilinear_Filter;
834 }
835
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000836 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000837 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000838 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000839
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000840 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000841 int scale;
842
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000843 enum {
844 kOffscreenStage = GrPaint::kTotalStages,
845 };
846
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000847 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000848 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000849 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000850 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851
852 // Do 2x2 downsample from first to second
853 target->setTexture(kOffscreenStage, src);
854 target->setRenderTarget(dst);
855 target->setViewMatrix(GrMatrix::I());
856 sampleM.setScale(scale * GR_Scalar1 / src->width(),
857 scale * GR_Scalar1 / src->height());
858 sampler.setMatrix(sampleM);
859 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000860 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
861 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000862 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
863
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000864 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000865 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000866 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000867 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000868 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000869 } else {
870 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
871 record->fDownsample);
872 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000873 }
874
bsalomon@google.com91958362011-06-13 17:58:13 +0000875 // setup for draw back to main RT, we use the original
876 // draw state setup by the caller plus an additional coverage
877 // stage to handle the AA resolve. Also, we use an identity
878 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000879 int stageMask = paint.getActiveStageMask();
880
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000881 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000882 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000883
884 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000885 GrMatrix invVM;
886 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000887 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000888 }
889 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000890 // This is important when tiling, otherwise second tile's
891 // pass 1 view matrix will be incorrect.
892 GrDrawTarget::AutoViewMatrixRestore avmr(target);
893
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000894 target->setViewMatrix(GrMatrix::I());
895
896 target->setTexture(kOffscreenStage, src);
897 sampleM.setScale(scale * GR_Scalar1 / src->width(),
898 scale * GR_Scalar1 / src->height());
899 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000900 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
901 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000902 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000903 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000904
reed@google.com20efde72011-05-09 17:00:02 +0000905 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000906 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000907 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000908 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000909}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000910
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000911void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
912 GrPathRenderer* pr,
913 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000914 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000915}
916
917////////////////////////////////////////////////////////////////////////////////
918
bsalomon@google.com27847de2011-02-22 20:59:41 +0000919/* create a triangle strip that strokes the specified triangle. There are 8
920 unique vertices, but we repreat the last 2 to close up. Alternatively we
921 could use an indices array, and then only send 8 verts, but not sure that
922 would be faster.
923 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000924static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000925 GrScalar width) {
926 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000927 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000928
929 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
930 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
931 verts[2].set(rect.fRight - rad, rect.fTop + rad);
932 verts[3].set(rect.fRight + rad, rect.fTop - rad);
933 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
934 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
935 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
936 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
937 verts[8] = verts[0];
938 verts[9] = verts[1];
939}
940
bsalomon@google.com205d4602011-04-25 12:43:45 +0000941static void setInsetFan(GrPoint* pts, size_t stride,
942 const GrRect& r, GrScalar dx, GrScalar dy) {
943 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
944}
945
946static const uint16_t gFillAARectIdx[] = {
947 0, 1, 5, 5, 4, 0,
948 1, 2, 6, 6, 5, 1,
949 2, 3, 7, 7, 6, 2,
950 3, 0, 4, 4, 7, 3,
951 4, 5, 6, 6, 7, 4,
952};
953
954int GrContext::aaFillRectIndexCount() const {
955 return GR_ARRAY_COUNT(gFillAARectIdx);
956}
957
958GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
959 if (NULL == fAAFillRectIndexBuffer) {
960 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
961 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000962 if (NULL != fAAFillRectIndexBuffer) {
963 #if GR_DEBUG
964 bool updated =
965 #endif
966 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
967 sizeof(gFillAARectIdx));
968 GR_DEBUGASSERT(updated);
969 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000970 }
971 return fAAFillRectIndexBuffer;
972}
973
974static const uint16_t gStrokeAARectIdx[] = {
975 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
976 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
977 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
978 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
979
980 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
981 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
982 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
983 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
984
985 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
986 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
987 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
988 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
989};
990
991int GrContext::aaStrokeRectIndexCount() const {
992 return GR_ARRAY_COUNT(gStrokeAARectIdx);
993}
994
995GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
996 if (NULL == fAAStrokeRectIndexBuffer) {
997 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
998 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000999 if (NULL != fAAStrokeRectIndexBuffer) {
1000 #if GR_DEBUG
1001 bool updated =
1002 #endif
1003 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1004 sizeof(gStrokeAARectIdx));
1005 GR_DEBUGASSERT(updated);
1006 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001007 }
1008 return fAAStrokeRectIndexBuffer;
1009}
1010
bsalomon@google.coma3108262011-10-10 14:08:47 +00001011static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1012 bool useCoverage) {
1013 GrVertexLayout layout = 0;
1014 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
1015 if (NULL != target->getTexture(s)) {
1016 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1017 }
1018 }
1019 if (useCoverage) {
1020 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1021 } else {
1022 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1023 }
1024 return layout;
1025}
1026
bsalomon@google.com205d4602011-04-25 12:43:45 +00001027void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001028 const GrRect& devRect,
1029 bool useVertexCoverage) {
1030 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001031
1032 size_t vsize = GrDrawTarget::VertexSize(layout);
1033
1034 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001035 if (!geo.succeeded()) {
1036 GrPrintf("Failed to get space for vertices!\n");
1037 return;
1038 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001039 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1040 if (NULL == indexBuffer) {
1041 GrPrintf("Failed to create index buffer!\n");
1042 return;
1043 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001044
1045 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1046
1047 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1048 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1049
1050 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1051 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1052
1053 verts += sizeof(GrPoint);
1054 for (int i = 0; i < 4; ++i) {
1055 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1056 }
1057
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 GrColor innerColor;
1059 if (useVertexCoverage) {
1060 innerColor = GrColorPackRGBA(0,0,0,0xff);
1061 } else {
1062 innerColor = target->getColor();
1063 }
1064
bsalomon@google.com205d4602011-04-25 12:43:45 +00001065 verts += 4 * vsize;
1066 for (int i = 0; i < 4; ++i) {
1067 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1068 }
1069
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001070 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001071
1072 target->drawIndexed(kTriangles_PrimitiveType, 0,
1073 0, 8, this->aaFillRectIndexCount());
1074}
1075
bsalomon@google.coma3108262011-10-10 14:08:47 +00001076void GrContext::strokeAARect(GrDrawTarget* target,
1077 const GrRect& devRect,
1078 const GrVec& devStrokeSize,
1079 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001080 const GrScalar& dx = devStrokeSize.fX;
1081 const GrScalar& dy = devStrokeSize.fY;
1082 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1083 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1084
bsalomon@google.com205d4602011-04-25 12:43:45 +00001085 GrScalar spare;
1086 {
1087 GrScalar w = devRect.width() - dx;
1088 GrScalar h = devRect.height() - dy;
1089 spare = GrMin(w, h);
1090 }
1091
1092 if (spare <= 0) {
1093 GrRect r(devRect);
1094 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001095 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001096 return;
1097 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001098 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001099 size_t vsize = GrDrawTarget::VertexSize(layout);
1100
1101 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001102 if (!geo.succeeded()) {
1103 GrPrintf("Failed to get space for vertices!\n");
1104 return;
1105 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001106 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1107 if (NULL == indexBuffer) {
1108 GrPrintf("Failed to create index buffer!\n");
1109 return;
1110 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001111
1112 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1113
1114 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1115 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1116 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1117 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1118
1119 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1120 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1121 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1122 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1123
1124 verts += sizeof(GrPoint);
1125 for (int i = 0; i < 4; ++i) {
1126 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1127 }
1128
bsalomon@google.coma3108262011-10-10 14:08:47 +00001129 GrColor innerColor;
1130 if (useVertexCoverage) {
1131 innerColor = GrColorPackRGBA(0,0,0,0xff);
1132 } else {
1133 innerColor = target->getColor();
1134 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001135 verts += 4 * vsize;
1136 for (int i = 0; i < 8; ++i) {
1137 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1138 }
1139
1140 verts += 8 * vsize;
1141 for (int i = 0; i < 8; ++i) {
1142 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1143 }
1144
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001145 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001146 target->drawIndexed(kTriangles_PrimitiveType,
1147 0, 0, 16, aaStrokeRectIndexCount());
1148}
1149
reed@google.com20efde72011-05-09 17:00:02 +00001150/**
1151 * Returns true if the rects edges are integer-aligned.
1152 */
1153static bool isIRect(const GrRect& r) {
1154 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1155 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1156}
1157
bsalomon@google.com205d4602011-04-25 12:43:45 +00001158static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001159 const GrRect& rect,
1160 GrScalar width,
1161 const GrMatrix* matrix,
1162 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001163 GrRect* devRect,
1164 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001165 // we use a simple alpha ramp to do aa on axis-aligned rects
1166 // do AA with alpha ramp if the caller requested AA, the rect
1167 // will be axis-aligned,the render target is not
1168 // multisampled, and the rect won't land on integer coords.
1169
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001170 if (!target->isAntialiasState()) {
1171 return false;
1172 }
1173
bsalomon@google.coma3108262011-10-10 14:08:47 +00001174 // we are keeping around the "tweak the alpha" trick because
1175 // it is our only hope for the fixed-pipe implementation.
1176 // In a shader implementation we can give a separate coverage input
1177 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001178 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001179 if (target->getCaps().fSupportPerVertexCoverage) {
1180 if (disable_coverage_aa_for_blend(target)) {
1181 GrPrintf("Turning off AA to correctly apply blend.\n");
1182 return false;
1183 } else {
1184 *useVertexCoverage = true;
1185 }
1186 } else {
1187 GrPrintf("Rect AA dropped because no support for coverage.\n");
1188 return false;
1189 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001190 }
1191
1192 if (target->getRenderTarget()->isMultisampled()) {
1193 return false;
1194 }
1195
bsalomon@google.com471d4712011-08-23 15:45:25 +00001196 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001197 return false;
1198 }
1199
1200 if (!target->getViewMatrix().preservesAxisAlignment()) {
1201 return false;
1202 }
1203
1204 if (NULL != matrix &&
1205 !matrix->preservesAxisAlignment()) {
1206 return false;
1207 }
1208
1209 *combinedMatrix = target->getViewMatrix();
1210 if (NULL != matrix) {
1211 combinedMatrix->preConcat(*matrix);
1212 GrAssert(combinedMatrix->preservesAxisAlignment());
1213 }
1214
1215 combinedMatrix->mapRect(devRect, rect);
1216 devRect->sort();
1217
1218 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001219 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001220 } else {
1221 return true;
1222 }
1223}
1224
bsalomon@google.com27847de2011-02-22 20:59:41 +00001225void GrContext::drawRect(const GrPaint& paint,
1226 const GrRect& rect,
1227 GrScalar width,
1228 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001229 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001230
1231 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001232 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233
bsalomon@google.com205d4602011-04-25 12:43:45 +00001234 GrRect devRect = rect;
1235 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001236 bool useVertexCoverage;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001237 bool doAA = apply_aa_to_rect(target, rect, width, matrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001238 &combinedMatrix, &devRect, &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001239
1240 if (doAA) {
1241 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001242 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001243 GrMatrix inv;
1244 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001245 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001246 }
1247 }
1248 target->setViewMatrix(GrMatrix::I());
1249 if (width >= 0) {
1250 GrVec strokeSize;;
1251 if (width > 0) {
1252 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001253 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001254 strokeSize.setAbs(strokeSize);
1255 } else {
1256 strokeSize.set(GR_Scalar1, GR_Scalar1);
1257 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001258 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001259 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001260 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001261 }
1262 return;
1263 }
1264
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265 if (width >= 0) {
1266 // TODO: consider making static vertex buffers for these cases.
1267 // Hairline could be done by just adding closing vertex to
1268 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001269 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1270
bsalomon@google.com27847de2011-02-22 20:59:41 +00001271 static const int worstCaseVertCount = 10;
1272 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1273
1274 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001275 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001276 return;
1277 }
1278
1279 GrPrimitiveType primType;
1280 int vertCount;
1281 GrPoint* vertex = geo.positions();
1282
1283 if (width > 0) {
1284 vertCount = 10;
1285 primType = kTriangleStrip_PrimitiveType;
1286 setStrokeRectStrip(vertex, rect, width);
1287 } else {
1288 // hairline
1289 vertCount = 5;
1290 primType = kLineStrip_PrimitiveType;
1291 vertex[0].set(rect.fLeft, rect.fTop);
1292 vertex[1].set(rect.fRight, rect.fTop);
1293 vertex[2].set(rect.fRight, rect.fBottom);
1294 vertex[3].set(rect.fLeft, rect.fBottom);
1295 vertex[4].set(rect.fLeft, rect.fTop);
1296 }
1297
1298 GrDrawTarget::AutoViewMatrixRestore avmr;
1299 if (NULL != matrix) {
1300 avmr.set(target);
1301 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001302 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001303 }
1304
1305 target->drawNonIndexed(primType, 0, vertCount);
1306 } else {
1307 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001308 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001309 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1310 if (NULL == sqVB) {
1311 GrPrintf("Failed to create static rect vb.\n");
1312 return;
1313 }
1314 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001315 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1316 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001317 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001318 0, rect.height(), rect.fTop,
1319 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001320
1321 if (NULL != matrix) {
1322 m.postConcat(*matrix);
1323 }
1324
1325 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001326 target->preConcatSamplerMatrices(stageMask, m);
1327
bsalomon@google.com27847de2011-02-22 20:59:41 +00001328 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1329 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001330 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 #endif
1332 }
1333}
1334
1335void GrContext::drawRectToRect(const GrPaint& paint,
1336 const GrRect& dstRect,
1337 const GrRect& srcRect,
1338 const GrMatrix* dstMatrix,
1339 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001340 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001341
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001342 // srcRect refers to paint's first texture
1343 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344 drawRect(paint, dstRect, -1, dstMatrix);
1345 return;
1346 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001347
bsalomon@google.com27847de2011-02-22 20:59:41 +00001348 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1349
1350#if GR_STATIC_RECT_VB
1351 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001352
1353 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001354 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1355
1356 GrMatrix m;
1357
1358 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1359 0, dstRect.height(), dstRect.fTop,
1360 0, 0, GrMatrix::I()[8]);
1361 if (NULL != dstMatrix) {
1362 m.postConcat(*dstMatrix);
1363 }
1364 target->preConcatViewMatrix(m);
1365
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001366 // srcRect refers to first stage
1367 int otherStageMask = paint.getActiveStageMask() &
1368 (~(1 << GrPaint::kFirstTextureStage));
1369 if (otherStageMask) {
1370 target->preConcatSamplerMatrices(otherStageMask, m);
1371 }
1372
bsalomon@google.com27847de2011-02-22 20:59:41 +00001373 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1374 0, srcRect.height(), srcRect.fTop,
1375 0, 0, GrMatrix::I()[8]);
1376 if (NULL != srcMatrix) {
1377 m.postConcat(*srcMatrix);
1378 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001379 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001380
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001381 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1382 if (NULL == sqVB) {
1383 GrPrintf("Failed to create static rect vb.\n");
1384 return;
1385 }
1386 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001387 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1388#else
1389
1390 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001391#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001392 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001393#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001394 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1395#endif
1396
1397 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1398 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1399 srcRects[0] = &srcRect;
1400 srcMatrices[0] = srcMatrix;
1401
1402 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1403#endif
1404}
1405
1406void GrContext::drawVertices(const GrPaint& paint,
1407 GrPrimitiveType primitiveType,
1408 int vertexCount,
1409 const GrPoint positions[],
1410 const GrPoint texCoords[],
1411 const GrColor colors[],
1412 const uint16_t indices[],
1413 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001414 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415
1416 GrDrawTarget::AutoReleaseGeometry geo;
1417
1418 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1419
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001420 bool hasTexCoords[GrPaint::kTotalStages] = {
1421 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1422 0 // remaining stages use positions
1423 };
1424
1425 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001426
1427 if (NULL != colors) {
1428 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001429 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001430 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001431
1432 if (sizeof(GrPoint) != vertexSize) {
1433 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001434 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001435 return;
1436 }
1437 int texOffsets[GrDrawTarget::kMaxTexCoords];
1438 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001439 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1440 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001441 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001442 NULL,
1443 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001444 void* curVertex = geo.vertices();
1445
1446 for (int i = 0; i < vertexCount; ++i) {
1447 *((GrPoint*)curVertex) = positions[i];
1448
1449 if (texOffsets[0] > 0) {
1450 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1451 }
1452 if (colorOffset > 0) {
1453 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1454 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001455 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001456 }
1457 } else {
1458 target->setVertexSourceToArray(layout, positions, vertexCount);
1459 }
1460
bsalomon@google.com91958362011-06-13 17:58:13 +00001461 // we don't currently apply offscreen AA to this path. Need improved
1462 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001463
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001464 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001465 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001466 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001467 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001468 target->drawNonIndexed(primitiveType, 0, vertexCount);
1469 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001470}
1471
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001472///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001473
reed@google.com07f3ee12011-05-16 17:21:57 +00001474void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1475 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001476
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001477 if (path.isEmpty()) {
1478#if GR_DEBUG
1479 GrPrintf("Empty path should have been caught by canvas.\n");
1480#endif
1481 if (GrIsFillInverted(fill)) {
1482 this->drawPaint(paint);
1483 }
1484 return;
1485 }
1486
bsalomon@google.com27847de2011-02-22 20:59:41 +00001487 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001488
1489 // An Assumption here is that path renderer would use some form of tweaking
1490 // the src color (either the input alpha or in the frag shader) to implement
1491 // aa. If we have some future driver-mojo path AA that can do the right
1492 // thing WRT to the blend then we'll need some query on the PR.
1493 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001494 GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001495 target->disableState(GrDrawTarget::kAntialias_StateBit);
1496 }
1497
bsalomon@google.com30085192011-08-19 15:42:31 +00001498 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1499 if (NULL == pr) {
1500 GrPrintf("Unable to find path renderer compatible with path.\n");
1501 return;
1502 }
1503
bsalomon@google.comee435122011-07-01 14:57:55 +00001504 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1505 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001506
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001507 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001508 this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001509
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001510 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001511
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001512 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001513 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1514 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001515 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001516 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001517 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001518 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001519 return;
1520 }
1521 }
reed@google.com70c136e2011-06-03 19:51:26 +00001522
reed@google.com07f3ee12011-05-16 17:21:57 +00001523 GrRect pathBounds = path.getBounds();
1524 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001525 if (NULL != translate) {
1526 pathBounds.offset(*translate);
1527 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001528 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001529 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001530 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001531 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001532 return;
1533 }
1534 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001535 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001536 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1537 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001538 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1539 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1540 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001541 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001542 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1543 }
1544 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001545 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001546 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001547 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1548 GrRect rect;
1549 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001550 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1551 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001552 target->drawSimpleRect(rect, NULL, stageMask);
1553 }
1554 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001555 rect.iset(clipIBounds.fLeft, bound.fTop,
1556 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001557 target->drawSimpleRect(rect, NULL, stageMask);
1558 }
1559 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001560 rect.iset(bound.fRight, bound.fTop,
1561 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001562 target->drawSimpleRect(rect, NULL, stageMask);
1563 }
1564 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001565 rect.iset(clipIBounds.fLeft, bound.fBottom,
1566 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001567 target->drawSimpleRect(rect, NULL, stageMask);
1568 }
1569 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001570 return;
1571 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001572 }
1573 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001574}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001575
bsalomon@google.com27847de2011-02-22 20:59:41 +00001576////////////////////////////////////////////////////////////////////////////////
1577
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001578bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001579 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001580}
1581
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001582void GrContext::flush(int flagsBitfield) {
1583 if (kDiscard_FlushBit & flagsBitfield) {
1584 fDrawBuffer->reset();
1585 } else {
1586 flushDrawBuffer();
1587 }
1588
1589 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001590 fGpu->forceRenderTargetFlush();
1591 }
1592}
1593
1594void GrContext::flushText() {
1595 if (kText_DrawCategory == fLastDrawCategory) {
1596 flushDrawBuffer();
1597 }
1598}
1599
1600void GrContext::flushDrawBuffer() {
1601#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001602 if (fDrawBuffer) {
1603 fDrawBuffer->playback(fGpu);
1604 fDrawBuffer->reset();
1605 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001606#endif
1607}
1608
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001609bool GrContext::readTexturePixels(GrTexture* texture,
1610 int left, int top, int width, int height,
1611 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001612 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001613
1614 // TODO: code read pixels for textures that aren't rendertargets
1615
1616 this->flush();
1617 GrRenderTarget* target = texture->asRenderTarget();
1618 if (NULL != target) {
1619 return fGpu->readPixels(target,
1620 left, top, width, height,
1621 config, buffer);
1622 } else {
1623 return false;
1624 }
1625}
1626
1627bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1628 int left, int top, int width, int height,
1629 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001630 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001631 uint32_t flushFlags = 0;
1632 if (NULL == target) {
1633 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1634 }
1635
1636 this->flush(flushFlags);
1637 return fGpu->readPixels(target,
1638 left, top, width, height,
1639 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001640}
1641
1642void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001643 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001644 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001645 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001646
1647 // TODO: when underlying api has a direct way to do this we should use it
1648 // (e.g. glDrawPixels on desktop GL).
1649
bsalomon@google.com5c638652011-07-18 19:31:59 +00001650 this->flush(true);
1651
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001652 const GrTextureDesc desc = {
1653 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001654 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001655 GrAutoScratchTexture ast(this, desc);
1656 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001657 if (NULL == texture) {
1658 return;
1659 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001660 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001661
bsalomon@google.com27847de2011-02-22 20:59:41 +00001662 GrDrawTarget::AutoStateRestore asr(fGpu);
1663
1664 GrMatrix matrix;
1665 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1666 fGpu->setViewMatrix(matrix);
1667
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001668 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001669 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1670 fGpu->setAlpha(0xFF);
1671 fGpu->setBlendFunc(kOne_BlendCoeff,
1672 kZero_BlendCoeff);
1673 fGpu->setTexture(0, texture);
1674
1675 GrSamplerState sampler;
1676 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001677 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001678 sampler.setMatrix(matrix);
1679 fGpu->setSamplerState(0, sampler);
1680
1681 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1682 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001683 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001684 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1685 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001686 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001687 return;
1688 }
1689 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1690 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1691}
1692////////////////////////////////////////////////////////////////////////////////
1693
1694void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001695
1696 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1697 int s = i + GrPaint::kFirstTextureStage;
1698 target->setTexture(s, paint.getTexture(i));
1699 target->setSamplerState(s, *paint.getTextureSampler(i));
1700 }
1701
1702 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1703
1704 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1705 int s = i + GrPaint::kFirstMaskStage;
1706 target->setTexture(s, paint.getMask(i));
1707 target->setSamplerState(s, *paint.getMaskSampler(i));
1708 }
1709
bsalomon@google.com27847de2011-02-22 20:59:41 +00001710 target->setColor(paint.fColor);
1711
1712 if (paint.fDither) {
1713 target->enableState(GrDrawTarget::kDither_StateBit);
1714 } else {
1715 target->disableState(GrDrawTarget::kDither_StateBit);
1716 }
1717 if (paint.fAntiAlias) {
1718 target->enableState(GrDrawTarget::kAntialias_StateBit);
1719 } else {
1720 target->disableState(GrDrawTarget::kAntialias_StateBit);
1721 }
1722 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001723 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001724
1725 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1726 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1727 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001728}
1729
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001730GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001731 DrawCategory category) {
1732 if (category != fLastDrawCategory) {
1733 flushDrawBuffer();
1734 fLastDrawCategory = category;
1735 }
1736 SetPaint(paint, fGpu);
1737 GrDrawTarget* target = fGpu;
1738 switch (category) {
1739 case kText_DrawCategory:
1740#if DEFER_TEXT_RENDERING
1741 target = fDrawBuffer;
1742 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1743#else
1744 target = fGpu;
1745#endif
1746 break;
1747 case kUnbuffered_DrawCategory:
1748 target = fGpu;
1749 break;
1750 case kBuffered_DrawCategory:
1751 target = fDrawBuffer;
1752 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1753 break;
1754 }
1755 return target;
1756}
1757
bsalomon@google.com30085192011-08-19 15:42:31 +00001758GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1759 const GrPath& path,
1760 GrPathFill fill) {
1761 if (NULL == fPathRendererChain) {
1762 fPathRendererChain =
1763 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1764 }
1765 return fPathRendererChain->getPathRenderer(target, path, fill);
1766}
1767
bsalomon@google.com27847de2011-02-22 20:59:41 +00001768////////////////////////////////////////////////////////////////////////////////
1769
bsalomon@google.com27847de2011-02-22 20:59:41 +00001770void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001771 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001772 fGpu->setRenderTarget(target);
1773}
1774
1775GrRenderTarget* GrContext::getRenderTarget() {
1776 return fGpu->getRenderTarget();
1777}
1778
1779const GrRenderTarget* GrContext::getRenderTarget() const {
1780 return fGpu->getRenderTarget();
1781}
1782
1783const GrMatrix& GrContext::getMatrix() const {
1784 return fGpu->getViewMatrix();
1785}
1786
1787void GrContext::setMatrix(const GrMatrix& m) {
1788 fGpu->setViewMatrix(m);
1789}
1790
1791void GrContext::concatMatrix(const GrMatrix& m) const {
1792 fGpu->preConcatViewMatrix(m);
1793}
1794
1795static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1796 intptr_t mask = 1 << shift;
1797 if (pred) {
1798 bits |= mask;
1799 } else {
1800 bits &= ~mask;
1801 }
1802 return bits;
1803}
1804
1805void GrContext::resetStats() {
1806 fGpu->resetStats();
1807}
1808
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001809const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001810 return fGpu->getStats();
1811}
1812
1813void GrContext::printStats() const {
1814 fGpu->printStats();
1815}
1816
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001817GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001818 fGpu = gpu;
1819 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001820 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001821
bsalomon@google.com30085192011-08-19 15:42:31 +00001822 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001823
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001824 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1825 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001826 fFontCache = new GrFontCache(fGpu);
1827
1828 fLastDrawCategory = kUnbuffered_DrawCategory;
1829
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001830 fDrawBuffer = NULL;
1831 fDrawBufferVBAllocPool = NULL;
1832 fDrawBufferIBAllocPool = NULL;
1833
bsalomon@google.com205d4602011-04-25 12:43:45 +00001834 fAAFillRectIndexBuffer = NULL;
1835 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001836
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001837 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1838 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001839 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1840 }
1841 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001842
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001843 this->setupDrawBuffer();
1844}
1845
1846void GrContext::setupDrawBuffer() {
1847
1848 GrAssert(NULL == fDrawBuffer);
1849 GrAssert(NULL == fDrawBufferVBAllocPool);
1850 GrAssert(NULL == fDrawBufferIBAllocPool);
1851
bsalomon@google.com27847de2011-02-22 20:59:41 +00001852#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001853 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001854 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001855 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1856 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001857 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001858 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001859 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001860 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1861
bsalomon@google.com471d4712011-08-23 15:45:25 +00001862 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1863 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001864 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001865#endif
1866
1867#if BATCH_RECT_TO_RECT
1868 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1869#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001870}
1871
bsalomon@google.com27847de2011-02-22 20:59:41 +00001872GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1873 GrDrawTarget* target;
1874#if DEFER_TEXT_RENDERING
1875 target = prepareToDraw(paint, kText_DrawCategory);
1876#else
1877 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1878#endif
1879 SetPaint(paint, target);
1880 return target;
1881}
1882
1883const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1884 return fGpu->getQuadIndexBuffer();
1885}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001886
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001887void GrContext::convolveInX(GrTexture* texture,
1888 const SkRect& rect,
1889 const float* kernel,
1890 int kernelWidth) {
1891 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1892 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1893}
1894
1895void GrContext::convolveInY(GrTexture* texture,
1896 const SkRect& rect,
1897 const float* kernel,
1898 int kernelWidth) {
1899 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1900 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1901}
1902
1903void GrContext::convolve(GrTexture* texture,
1904 const SkRect& rect,
1905 float imageIncrement[2],
1906 const float* kernel,
1907 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001908 GrDrawTarget::AutoStateRestore asr(fGpu);
1909 GrMatrix sampleM;
1910 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1911 GrSamplerState::kClamp_WrapMode,
1912 GrSamplerState::kConvolution_Filter);
1913 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001914 sampleM.setScale(GR_Scalar1 / texture->width(),
1915 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001916 sampler.setMatrix(sampleM);
1917 fGpu->setSamplerState(0, sampler);
1918 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001919 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001920 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001921 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1922}