blob: d9fb9e85c8f2133bb414699e8e744616fbb4c1c9 [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.com8295dc12011-05-02 12:53:34 +0000680 return false;
681 }
682 return true;
683#endif
684}
685
bsalomon@google.com91958362011-06-13 17:58:13 +0000686bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000687 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000688 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000689 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000690 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000691
692 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000693
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000694 GrAssert(NULL == record->fOffscreen0.texture());
695 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000696 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000697
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000698 int boundW = boundRect.width();
699 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000700
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000701 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000702
703 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
704 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
705
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000706 if (requireStencil) {
707 desc.fFlags = kRenderTarget_GrTextureFlagBit;
708 } else {
709 desc.fFlags = kRenderTarget_GrTextureFlagBit |
710 kNoStencil_GrTextureFlagBit;
711 }
712
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000713 desc.fFormat = kRGBA_8888_GrPixelConfig;
714
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000715 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000716 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000717 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000718 desc.fAALevel = kMed_GrAALevel;
719 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000720 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000721 OffscreenRecord::k4x4SinglePass_Downsample :
722 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000723 record->fScale = OFFSCREEN_SSAA_SCALE;
724 // both downsample paths assume this
725 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000726 desc.fAALevel = kNone_GrAALevel;
727 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000728
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000729 desc.fWidth *= record->fScale;
730 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000731 record->fOffscreen0.set(this, desc);
732 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000733 return false;
734 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000735 // the approximate lookup might have given us some slop space, might as well
736 // use it when computing the tiles size.
737 // these are scale values, will adjust after considering
738 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000739 record->fTileSizeX = record->fOffscreen0.texture()->width();
740 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000741
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000742 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000743 desc.fWidth /= 2;
744 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000745 record->fOffscreen1.set(this, desc);
746 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000747 return false;
748 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000749 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000750 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000751 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000752 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000753 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000754 record->fTileSizeX /= record->fScale;
755 record->fTileSizeY /= record->fScale;
756
757 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
758 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
759
tomhudson@google.com237a4612011-07-19 15:44:00 +0000760 record->fClip = target->getClip();
761
bsalomon@google.com91958362011-06-13 17:58:13 +0000762 target->saveCurrentDrawState(&record->fSavedState);
763 return true;
764}
765
766void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
767 const GrIRect& boundRect,
768 int tileX, int tileY,
769 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000770
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000771 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000772 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000773
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000774 GrPaint tempPaint;
775 tempPaint.reset();
776 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000777 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000778
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000779 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000780 int left = boundRect.fLeft + tileX * record->fTileSizeX;
781 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000782 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000783 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000784 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000785 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000786 target->postConcatViewMatrix(scaleM);
787
bsalomon@google.com91958362011-06-13 17:58:13 +0000788 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000789 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000790 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000791 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000792 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
793 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000794 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000795#if 0
796 // visualize tile boundaries by setting edges of offscreen to white
797 // and interior to tranparent. black.
798 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000799
bsalomon@google.com91958362011-06-13 17:58:13 +0000800 static const int gOffset = 2;
801 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
802 record->fScale * w - gOffset,
803 record->fScale * h - gOffset);
804 target->clear(&clear2, 0x0);
805#else
806 target->clear(&clear, 0x0);
807#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000808}
809
bsalomon@google.com91958362011-06-13 17:58:13 +0000810void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000811 const GrPaint& paint,
812 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000813 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000814 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000815 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000816 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000817 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000818 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000819 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
820 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000821 tileRect.fRight = (tileX == record->fTileCountX-1) ?
822 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000823 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000824 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
825 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000826 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000827
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000828 GrSamplerState::Filter filter;
829 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
830 filter = GrSamplerState::k4x4Downsample_Filter;
831 } else {
832 filter = GrSamplerState::kBilinear_Filter;
833 }
834
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000835 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000836 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000837 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000838
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000839 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000840 int scale;
841
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000842 enum {
843 kOffscreenStage = GrPaint::kTotalStages,
844 };
845
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000846 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000847 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000848 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000849 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000850
851 // Do 2x2 downsample from first to second
852 target->setTexture(kOffscreenStage, src);
853 target->setRenderTarget(dst);
854 target->setViewMatrix(GrMatrix::I());
855 sampleM.setScale(scale * GR_Scalar1 / src->width(),
856 scale * GR_Scalar1 / src->height());
857 sampler.setMatrix(sampleM);
858 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000859 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
860 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000861 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
862
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000863 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000864 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000865 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000866 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000867 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000868 } else {
869 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
870 record->fDownsample);
871 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 }
873
bsalomon@google.com91958362011-06-13 17:58:13 +0000874 // setup for draw back to main RT, we use the original
875 // draw state setup by the caller plus an additional coverage
876 // stage to handle the AA resolve. Also, we use an identity
877 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000878 int stageMask = paint.getActiveStageMask();
879
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000880 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000881 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000882
883 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000884 GrMatrix invVM;
885 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000886 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000887 }
888 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000889 // This is important when tiling, otherwise second tile's
890 // pass 1 view matrix will be incorrect.
891 GrDrawTarget::AutoViewMatrixRestore avmr(target);
892
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000893 target->setViewMatrix(GrMatrix::I());
894
895 target->setTexture(kOffscreenStage, src);
896 sampleM.setScale(scale * GR_Scalar1 / src->width(),
897 scale * GR_Scalar1 / src->height());
898 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000899 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
900 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000901 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000902 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000903
reed@google.com20efde72011-05-09 17:00:02 +0000904 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000905 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000906 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000907 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000908}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000909
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000910void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
911 GrPathRenderer* pr,
912 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000913 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000914}
915
916////////////////////////////////////////////////////////////////////////////////
917
bsalomon@google.com27847de2011-02-22 20:59:41 +0000918/* create a triangle strip that strokes the specified triangle. There are 8
919 unique vertices, but we repreat the last 2 to close up. Alternatively we
920 could use an indices array, and then only send 8 verts, but not sure that
921 would be faster.
922 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000923static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000924 GrScalar width) {
925 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000926 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000927
928 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
929 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
930 verts[2].set(rect.fRight - rad, rect.fTop + rad);
931 verts[3].set(rect.fRight + rad, rect.fTop - rad);
932 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
933 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
934 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
935 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
936 verts[8] = verts[0];
937 verts[9] = verts[1];
938}
939
bsalomon@google.com205d4602011-04-25 12:43:45 +0000940static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000941 // FIXME: This was copied from SkGpuDevice, seems like
942 // we should have already smeared a in caller if that
943 // is what is desired.
944 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000945 unsigned a = GrColorUnpackA(paint.fColor);
946 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000947 } else {
948 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000949 }
950}
951
952static void setInsetFan(GrPoint* pts, size_t stride,
953 const GrRect& r, GrScalar dx, GrScalar dy) {
954 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
955}
956
957static const uint16_t gFillAARectIdx[] = {
958 0, 1, 5, 5, 4, 0,
959 1, 2, 6, 6, 5, 1,
960 2, 3, 7, 7, 6, 2,
961 3, 0, 4, 4, 7, 3,
962 4, 5, 6, 6, 7, 4,
963};
964
965int GrContext::aaFillRectIndexCount() const {
966 return GR_ARRAY_COUNT(gFillAARectIdx);
967}
968
969GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
970 if (NULL == fAAFillRectIndexBuffer) {
971 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
972 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000973 if (NULL != fAAFillRectIndexBuffer) {
974 #if GR_DEBUG
975 bool updated =
976 #endif
977 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
978 sizeof(gFillAARectIdx));
979 GR_DEBUGASSERT(updated);
980 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000981 }
982 return fAAFillRectIndexBuffer;
983}
984
985static const uint16_t gStrokeAARectIdx[] = {
986 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
987 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
988 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
989 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
990
991 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
992 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
993 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
994 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
995
996 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
997 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
998 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
999 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1000};
1001
1002int GrContext::aaStrokeRectIndexCount() const {
1003 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1004}
1005
1006GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1007 if (NULL == fAAStrokeRectIndexBuffer) {
1008 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1009 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001010 if (NULL != fAAStrokeRectIndexBuffer) {
1011 #if GR_DEBUG
1012 bool updated =
1013 #endif
1014 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1015 sizeof(gStrokeAARectIdx));
1016 GR_DEBUGASSERT(updated);
1017 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001018 }
1019 return fAAStrokeRectIndexBuffer;
1020}
1021
1022void GrContext::fillAARect(GrDrawTarget* target,
1023 const GrPaint& paint,
1024 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001025 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1026 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001027
1028 size_t vsize = GrDrawTarget::VertexSize(layout);
1029
1030 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001031 if (!geo.succeeded()) {
1032 GrPrintf("Failed to get space for vertices!\n");
1033 return;
1034 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001035 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1036 if (NULL == indexBuffer) {
1037 GrPrintf("Failed to create index buffer!\n");
1038 return;
1039 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001040
1041 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1042
1043 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1044 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1045
1046 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1047 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1048
1049 verts += sizeof(GrPoint);
1050 for (int i = 0; i < 4; ++i) {
1051 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1052 }
1053
1054 GrColor innerColor = getColorForMesh(paint);
1055 verts += 4 * vsize;
1056 for (int i = 0; i < 4; ++i) {
1057 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1058 }
1059
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001060 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001061
1062 target->drawIndexed(kTriangles_PrimitiveType, 0,
1063 0, 8, this->aaFillRectIndexCount());
1064}
1065
1066void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1067 const GrRect& devRect, const GrVec& devStrokeSize) {
1068 const GrScalar& dx = devStrokeSize.fX;
1069 const GrScalar& dy = devStrokeSize.fY;
1070 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1071 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1072
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001073 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1074 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001075
1076 GrScalar spare;
1077 {
1078 GrScalar w = devRect.width() - dx;
1079 GrScalar h = devRect.height() - dy;
1080 spare = GrMin(w, h);
1081 }
1082
1083 if (spare <= 0) {
1084 GrRect r(devRect);
1085 r.inset(-rx, -ry);
1086 fillAARect(target, paint, r);
1087 return;
1088 }
1089
1090 size_t vsize = GrDrawTarget::VertexSize(layout);
1091
1092 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001093 if (!geo.succeeded()) {
1094 GrPrintf("Failed to get space for vertices!\n");
1095 return;
1096 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001097 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1098 if (NULL == indexBuffer) {
1099 GrPrintf("Failed to create index buffer!\n");
1100 return;
1101 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001102
1103 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1104
1105 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1106 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1107 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1108 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1109
1110 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1111 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1112 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1113 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1114
1115 verts += sizeof(GrPoint);
1116 for (int i = 0; i < 4; ++i) {
1117 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1118 }
1119
1120 GrColor innerColor = getColorForMesh(paint);
1121 verts += 4 * vsize;
1122 for (int i = 0; i < 8; ++i) {
1123 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1124 }
1125
1126 verts += 8 * vsize;
1127 for (int i = 0; i < 8; ++i) {
1128 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1129 }
1130
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001131 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001132 target->drawIndexed(kTriangles_PrimitiveType,
1133 0, 0, 16, aaStrokeRectIndexCount());
1134}
1135
reed@google.com20efde72011-05-09 17:00:02 +00001136/**
1137 * Returns true if the rects edges are integer-aligned.
1138 */
1139static bool isIRect(const GrRect& r) {
1140 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1141 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1142}
1143
bsalomon@google.com205d4602011-04-25 12:43:45 +00001144static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001145 const GrRect& rect,
1146 GrScalar width,
1147 const GrMatrix* matrix,
1148 GrMatrix* combinedMatrix,
1149 GrRect* devRect) {
1150 // we use a simple alpha ramp to do aa on axis-aligned rects
1151 // do AA with alpha ramp if the caller requested AA, the rect
1152 // will be axis-aligned,the render target is not
1153 // multisampled, and the rect won't land on integer coords.
1154
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001155 if (!target->isAntialiasState()) {
1156 return false;
1157 }
1158
1159 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001160 return false;
1161 }
1162
1163 if (target->getRenderTarget()->isMultisampled()) {
1164 return false;
1165 }
1166
bsalomon@google.com471d4712011-08-23 15:45:25 +00001167 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001168 return false;
1169 }
1170
1171 if (!target->getViewMatrix().preservesAxisAlignment()) {
1172 return false;
1173 }
1174
1175 if (NULL != matrix &&
1176 !matrix->preservesAxisAlignment()) {
1177 return false;
1178 }
1179
1180 *combinedMatrix = target->getViewMatrix();
1181 if (NULL != matrix) {
1182 combinedMatrix->preConcat(*matrix);
1183 GrAssert(combinedMatrix->preservesAxisAlignment());
1184 }
1185
1186 combinedMatrix->mapRect(devRect, rect);
1187 devRect->sort();
1188
1189 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001190 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001191 } else {
1192 return true;
1193 }
1194}
1195
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196void GrContext::drawRect(const GrPaint& paint,
1197 const GrRect& rect,
1198 GrScalar width,
1199 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001200 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001201
1202 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001203 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001204
bsalomon@google.com205d4602011-04-25 12:43:45 +00001205 GrRect devRect = rect;
1206 GrMatrix combinedMatrix;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001207 bool doAA = apply_aa_to_rect(target, rect, width, matrix,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001208 &combinedMatrix, &devRect);
1209
1210 if (doAA) {
1211 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001212 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001213 GrMatrix inv;
1214 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001215 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001216 }
1217 }
1218 target->setViewMatrix(GrMatrix::I());
1219 if (width >= 0) {
1220 GrVec strokeSize;;
1221 if (width > 0) {
1222 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001223 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001224 strokeSize.setAbs(strokeSize);
1225 } else {
1226 strokeSize.set(GR_Scalar1, GR_Scalar1);
1227 }
1228 strokeAARect(target, paint, devRect, strokeSize);
1229 } else {
1230 fillAARect(target, paint, devRect);
1231 }
1232 return;
1233 }
1234
bsalomon@google.com27847de2011-02-22 20:59:41 +00001235 if (width >= 0) {
1236 // TODO: consider making static vertex buffers for these cases.
1237 // Hairline could be done by just adding closing vertex to
1238 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001239 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1240
bsalomon@google.com27847de2011-02-22 20:59:41 +00001241 static const int worstCaseVertCount = 10;
1242 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1243
1244 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001245 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001246 return;
1247 }
1248
1249 GrPrimitiveType primType;
1250 int vertCount;
1251 GrPoint* vertex = geo.positions();
1252
1253 if (width > 0) {
1254 vertCount = 10;
1255 primType = kTriangleStrip_PrimitiveType;
1256 setStrokeRectStrip(vertex, rect, width);
1257 } else {
1258 // hairline
1259 vertCount = 5;
1260 primType = kLineStrip_PrimitiveType;
1261 vertex[0].set(rect.fLeft, rect.fTop);
1262 vertex[1].set(rect.fRight, rect.fTop);
1263 vertex[2].set(rect.fRight, rect.fBottom);
1264 vertex[3].set(rect.fLeft, rect.fBottom);
1265 vertex[4].set(rect.fLeft, rect.fTop);
1266 }
1267
1268 GrDrawTarget::AutoViewMatrixRestore avmr;
1269 if (NULL != matrix) {
1270 avmr.set(target);
1271 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001272 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001273 }
1274
1275 target->drawNonIndexed(primType, 0, vertCount);
1276 } else {
1277 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001278 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001279 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1280 if (NULL == sqVB) {
1281 GrPrintf("Failed to create static rect vb.\n");
1282 return;
1283 }
1284 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001285 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1286 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001287 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001288 0, rect.height(), rect.fTop,
1289 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001290
1291 if (NULL != matrix) {
1292 m.postConcat(*matrix);
1293 }
1294
1295 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001296 target->preConcatSamplerMatrices(stageMask, m);
1297
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1299 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001300 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001301 #endif
1302 }
1303}
1304
1305void GrContext::drawRectToRect(const GrPaint& paint,
1306 const GrRect& dstRect,
1307 const GrRect& srcRect,
1308 const GrMatrix* dstMatrix,
1309 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001310 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001311
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001312 // srcRect refers to paint's first texture
1313 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314 drawRect(paint, dstRect, -1, dstMatrix);
1315 return;
1316 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001317
bsalomon@google.com27847de2011-02-22 20:59:41 +00001318 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1319
1320#if GR_STATIC_RECT_VB
1321 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001322
1323 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1325
1326 GrMatrix m;
1327
1328 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1329 0, dstRect.height(), dstRect.fTop,
1330 0, 0, GrMatrix::I()[8]);
1331 if (NULL != dstMatrix) {
1332 m.postConcat(*dstMatrix);
1333 }
1334 target->preConcatViewMatrix(m);
1335
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001336 // srcRect refers to first stage
1337 int otherStageMask = paint.getActiveStageMask() &
1338 (~(1 << GrPaint::kFirstTextureStage));
1339 if (otherStageMask) {
1340 target->preConcatSamplerMatrices(otherStageMask, m);
1341 }
1342
bsalomon@google.com27847de2011-02-22 20:59:41 +00001343 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1344 0, srcRect.height(), srcRect.fTop,
1345 0, 0, GrMatrix::I()[8]);
1346 if (NULL != srcMatrix) {
1347 m.postConcat(*srcMatrix);
1348 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001349 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001350
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001351 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1352 if (NULL == sqVB) {
1353 GrPrintf("Failed to create static rect vb.\n");
1354 return;
1355 }
1356 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001357 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1358#else
1359
1360 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001361#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001362 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001363#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001364 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1365#endif
1366
1367 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1368 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1369 srcRects[0] = &srcRect;
1370 srcMatrices[0] = srcMatrix;
1371
1372 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1373#endif
1374}
1375
1376void GrContext::drawVertices(const GrPaint& paint,
1377 GrPrimitiveType primitiveType,
1378 int vertexCount,
1379 const GrPoint positions[],
1380 const GrPoint texCoords[],
1381 const GrColor colors[],
1382 const uint16_t indices[],
1383 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001384 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001385
1386 GrDrawTarget::AutoReleaseGeometry geo;
1387
1388 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1389
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001390 bool hasTexCoords[GrPaint::kTotalStages] = {
1391 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1392 0 // remaining stages use positions
1393 };
1394
1395 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001396
1397 if (NULL != colors) {
1398 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001399 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001400 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001401
1402 if (sizeof(GrPoint) != vertexSize) {
1403 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001404 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405 return;
1406 }
1407 int texOffsets[GrDrawTarget::kMaxTexCoords];
1408 int colorOffset;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001409 int edgeOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001410 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1411 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001412 &colorOffset,
1413 &edgeOffset);
1414 GrAssert(-1 == edgeOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 void* curVertex = geo.vertices();
1416
1417 for (int i = 0; i < vertexCount; ++i) {
1418 *((GrPoint*)curVertex) = positions[i];
1419
1420 if (texOffsets[0] > 0) {
1421 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1422 }
1423 if (colorOffset > 0) {
1424 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1425 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001426 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001427 }
1428 } else {
1429 target->setVertexSourceToArray(layout, positions, vertexCount);
1430 }
1431
bsalomon@google.com91958362011-06-13 17:58:13 +00001432 // we don't currently apply offscreen AA to this path. Need improved
1433 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001434
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001435 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001436 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001437 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001438 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001439 target->drawNonIndexed(primitiveType, 0, vertexCount);
1440 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441}
1442
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001443///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001444
reed@google.com07f3ee12011-05-16 17:21:57 +00001445void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1446 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001447
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001448 if (path.isEmpty()) {
1449#if GR_DEBUG
1450 GrPrintf("Empty path should have been caught by canvas.\n");
1451#endif
1452 if (GrIsFillInverted(fill)) {
1453 this->drawPaint(paint);
1454 }
1455 return;
1456 }
1457
bsalomon@google.com27847de2011-02-22 20:59:41 +00001458 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001459
1460 // An Assumption here is that path renderer would use some form of tweaking
1461 // the src color (either the input alpha or in the frag shader) to implement
1462 // aa. If we have some future driver-mojo path AA that can do the right
1463 // thing WRT to the blend then we'll need some query on the PR.
1464 if (disable_coverage_aa_for_blend(target)) {
1465 target->disableState(GrDrawTarget::kAntialias_StateBit);
1466 }
1467
bsalomon@google.com30085192011-08-19 15:42:31 +00001468 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1469 if (NULL == pr) {
1470 GrPrintf("Unable to find path renderer compatible with path.\n");
1471 return;
1472 }
1473
bsalomon@google.comee435122011-07-01 14:57:55 +00001474 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1475 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001476
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001477 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001478 this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001479
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001480 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001481
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001482 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001483 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1484 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001485 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001486 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001487 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001488 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001489 return;
1490 }
1491 }
reed@google.com70c136e2011-06-03 19:51:26 +00001492
reed@google.com07f3ee12011-05-16 17:21:57 +00001493 GrRect pathBounds = path.getBounds();
1494 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001495 if (NULL != translate) {
1496 pathBounds.offset(*translate);
1497 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001498 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001499 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001500 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001501 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001502 return;
1503 }
1504 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001505 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001506 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1507 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001508 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1509 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1510 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001511 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001512 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1513 }
1514 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001515 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001516 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001517 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1518 GrRect rect;
1519 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001520 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1521 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001522 target->drawSimpleRect(rect, NULL, stageMask);
1523 }
1524 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001525 rect.iset(clipIBounds.fLeft, bound.fTop,
1526 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001527 target->drawSimpleRect(rect, NULL, stageMask);
1528 }
1529 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001530 rect.iset(bound.fRight, bound.fTop,
1531 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001532 target->drawSimpleRect(rect, NULL, stageMask);
1533 }
1534 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001535 rect.iset(clipIBounds.fLeft, bound.fBottom,
1536 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001537 target->drawSimpleRect(rect, NULL, stageMask);
1538 }
1539 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001540 return;
1541 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001542 }
1543 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001544}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001545
bsalomon@google.com27847de2011-02-22 20:59:41 +00001546////////////////////////////////////////////////////////////////////////////////
1547
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001548bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001549 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001550}
1551
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001552void GrContext::flush(int flagsBitfield) {
1553 if (kDiscard_FlushBit & flagsBitfield) {
1554 fDrawBuffer->reset();
1555 } else {
1556 flushDrawBuffer();
1557 }
1558
1559 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001560 fGpu->forceRenderTargetFlush();
1561 }
1562}
1563
1564void GrContext::flushText() {
1565 if (kText_DrawCategory == fLastDrawCategory) {
1566 flushDrawBuffer();
1567 }
1568}
1569
1570void GrContext::flushDrawBuffer() {
1571#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001572 if (fDrawBuffer) {
1573 fDrawBuffer->playback(fGpu);
1574 fDrawBuffer->reset();
1575 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001576#endif
1577}
1578
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001579bool GrContext::readTexturePixels(GrTexture* texture,
1580 int left, int top, int width, int height,
1581 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001582 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001583
1584 // TODO: code read pixels for textures that aren't rendertargets
1585
1586 this->flush();
1587 GrRenderTarget* target = texture->asRenderTarget();
1588 if (NULL != target) {
1589 return fGpu->readPixels(target,
1590 left, top, width, height,
1591 config, buffer);
1592 } else {
1593 return false;
1594 }
1595}
1596
1597bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1598 int left, int top, int width, int height,
1599 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001600 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001601 uint32_t flushFlags = 0;
1602 if (NULL == target) {
1603 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1604 }
1605
1606 this->flush(flushFlags);
1607 return fGpu->readPixels(target,
1608 left, top, width, height,
1609 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001610}
1611
1612void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001613 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001615 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001616
1617 // TODO: when underlying api has a direct way to do this we should use it
1618 // (e.g. glDrawPixels on desktop GL).
1619
bsalomon@google.com5c638652011-07-18 19:31:59 +00001620 this->flush(true);
1621
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001622 const GrTextureDesc desc = {
1623 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001624 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001625 GrAutoScratchTexture ast(this, desc);
1626 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001627 if (NULL == texture) {
1628 return;
1629 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001630 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001631
bsalomon@google.com27847de2011-02-22 20:59:41 +00001632 GrDrawTarget::AutoStateRestore asr(fGpu);
1633
1634 GrMatrix matrix;
1635 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1636 fGpu->setViewMatrix(matrix);
1637
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001638 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001639 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1640 fGpu->setAlpha(0xFF);
1641 fGpu->setBlendFunc(kOne_BlendCoeff,
1642 kZero_BlendCoeff);
1643 fGpu->setTexture(0, texture);
1644
1645 GrSamplerState sampler;
1646 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001647 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001648 sampler.setMatrix(matrix);
1649 fGpu->setSamplerState(0, sampler);
1650
1651 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1652 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001653 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001654 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1655 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001656 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001657 return;
1658 }
1659 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1660 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1661}
1662////////////////////////////////////////////////////////////////////////////////
1663
1664void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001665
1666 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1667 int s = i + GrPaint::kFirstTextureStage;
1668 target->setTexture(s, paint.getTexture(i));
1669 target->setSamplerState(s, *paint.getTextureSampler(i));
1670 }
1671
1672 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1673
1674 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1675 int s = i + GrPaint::kFirstMaskStage;
1676 target->setTexture(s, paint.getMask(i));
1677 target->setSamplerState(s, *paint.getMaskSampler(i));
1678 }
1679
bsalomon@google.com27847de2011-02-22 20:59:41 +00001680 target->setColor(paint.fColor);
1681
1682 if (paint.fDither) {
1683 target->enableState(GrDrawTarget::kDither_StateBit);
1684 } else {
1685 target->disableState(GrDrawTarget::kDither_StateBit);
1686 }
1687 if (paint.fAntiAlias) {
1688 target->enableState(GrDrawTarget::kAntialias_StateBit);
1689 } else {
1690 target->disableState(GrDrawTarget::kAntialias_StateBit);
1691 }
1692 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001693 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001694
1695 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1696 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1697 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001698}
1699
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001700GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001701 DrawCategory category) {
1702 if (category != fLastDrawCategory) {
1703 flushDrawBuffer();
1704 fLastDrawCategory = category;
1705 }
1706 SetPaint(paint, fGpu);
1707 GrDrawTarget* target = fGpu;
1708 switch (category) {
1709 case kText_DrawCategory:
1710#if DEFER_TEXT_RENDERING
1711 target = fDrawBuffer;
1712 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1713#else
1714 target = fGpu;
1715#endif
1716 break;
1717 case kUnbuffered_DrawCategory:
1718 target = fGpu;
1719 break;
1720 case kBuffered_DrawCategory:
1721 target = fDrawBuffer;
1722 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1723 break;
1724 }
1725 return target;
1726}
1727
bsalomon@google.com30085192011-08-19 15:42:31 +00001728GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1729 const GrPath& path,
1730 GrPathFill fill) {
1731 if (NULL == fPathRendererChain) {
1732 fPathRendererChain =
1733 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1734 }
1735 return fPathRendererChain->getPathRenderer(target, path, fill);
1736}
1737
bsalomon@google.com27847de2011-02-22 20:59:41 +00001738////////////////////////////////////////////////////////////////////////////////
1739
bsalomon@google.com27847de2011-02-22 20:59:41 +00001740void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001741 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001742 fGpu->setRenderTarget(target);
1743}
1744
1745GrRenderTarget* GrContext::getRenderTarget() {
1746 return fGpu->getRenderTarget();
1747}
1748
1749const GrRenderTarget* GrContext::getRenderTarget() const {
1750 return fGpu->getRenderTarget();
1751}
1752
1753const GrMatrix& GrContext::getMatrix() const {
1754 return fGpu->getViewMatrix();
1755}
1756
1757void GrContext::setMatrix(const GrMatrix& m) {
1758 fGpu->setViewMatrix(m);
1759}
1760
1761void GrContext::concatMatrix(const GrMatrix& m) const {
1762 fGpu->preConcatViewMatrix(m);
1763}
1764
1765static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1766 intptr_t mask = 1 << shift;
1767 if (pred) {
1768 bits |= mask;
1769 } else {
1770 bits &= ~mask;
1771 }
1772 return bits;
1773}
1774
1775void GrContext::resetStats() {
1776 fGpu->resetStats();
1777}
1778
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001779const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001780 return fGpu->getStats();
1781}
1782
1783void GrContext::printStats() const {
1784 fGpu->printStats();
1785}
1786
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001787GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001788 fGpu = gpu;
1789 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001790 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001791
bsalomon@google.com30085192011-08-19 15:42:31 +00001792 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001793
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001794 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1795 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001796 fFontCache = new GrFontCache(fGpu);
1797
1798 fLastDrawCategory = kUnbuffered_DrawCategory;
1799
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001800 fDrawBuffer = NULL;
1801 fDrawBufferVBAllocPool = NULL;
1802 fDrawBufferIBAllocPool = NULL;
1803
bsalomon@google.com205d4602011-04-25 12:43:45 +00001804 fAAFillRectIndexBuffer = NULL;
1805 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001806
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001807 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1808 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001809 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1810 }
1811 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001812
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001813 this->setupDrawBuffer();
1814}
1815
1816void GrContext::setupDrawBuffer() {
1817
1818 GrAssert(NULL == fDrawBuffer);
1819 GrAssert(NULL == fDrawBufferVBAllocPool);
1820 GrAssert(NULL == fDrawBufferIBAllocPool);
1821
bsalomon@google.com27847de2011-02-22 20:59:41 +00001822#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001823 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001824 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001825 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1826 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001827 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001828 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001829 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001830 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1831
bsalomon@google.com471d4712011-08-23 15:45:25 +00001832 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1833 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001834 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001835#endif
1836
1837#if BATCH_RECT_TO_RECT
1838 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1839#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001840}
1841
bsalomon@google.com27847de2011-02-22 20:59:41 +00001842GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1843 GrDrawTarget* target;
1844#if DEFER_TEXT_RENDERING
1845 target = prepareToDraw(paint, kText_DrawCategory);
1846#else
1847 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1848#endif
1849 SetPaint(paint, target);
1850 return target;
1851}
1852
1853const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1854 return fGpu->getQuadIndexBuffer();
1855}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001856
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001857void GrContext::convolveInX(GrTexture* texture,
1858 const SkRect& rect,
1859 const float* kernel,
1860 int kernelWidth) {
1861 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1862 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1863}
1864
1865void GrContext::convolveInY(GrTexture* texture,
1866 const SkRect& rect,
1867 const float* kernel,
1868 int kernelWidth) {
1869 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1870 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1871}
1872
1873void GrContext::convolve(GrTexture* texture,
1874 const SkRect& rect,
1875 float imageIncrement[2],
1876 const float* kernel,
1877 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001878 GrDrawTarget::AutoStateRestore asr(fGpu);
1879 GrMatrix sampleM;
1880 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1881 GrSamplerState::kClamp_WrapMode,
1882 GrSamplerState::kConvolution_Filter);
1883 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001884 sampleM.setScale(GR_Scalar1 / texture->width(),
1885 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001886 sampler.setMatrix(sampleM);
1887 fGpu->setSamplerState(0, sampler);
1888 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001889 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001890 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001891 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1892}