blob: 23ad9e1fcedc7b92231375f24fd960c815835da6 [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?
34#define DISABLE_COVERAGE_AA_FOR_BLEND 0
35
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.com91958362011-06-13 17:58:13 +0000859 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
860 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.com91958362011-06-13 17:58:13 +0000899 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000900 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000901 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000902
reed@google.com20efde72011-05-09 17:00:02 +0000903 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000904 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000905 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000906 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000907}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000908
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000909void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
910 GrPathRenderer* pr,
911 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000912 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000913}
914
915////////////////////////////////////////////////////////////////////////////////
916
bsalomon@google.com27847de2011-02-22 20:59:41 +0000917/* create a triangle strip that strokes the specified triangle. There are 8
918 unique vertices, but we repreat the last 2 to close up. Alternatively we
919 could use an indices array, and then only send 8 verts, but not sure that
920 would be faster.
921 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000922static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000923 GrScalar width) {
924 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000925 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000926
927 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
928 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
929 verts[2].set(rect.fRight - rad, rect.fTop + rad);
930 verts[3].set(rect.fRight + rad, rect.fTop - rad);
931 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
932 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
933 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
934 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
935 verts[8] = verts[0];
936 verts[9] = verts[1];
937}
938
bsalomon@google.com205d4602011-04-25 12:43:45 +0000939static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000940 // FIXME: This was copied from SkGpuDevice, seems like
941 // we should have already smeared a in caller if that
942 // is what is desired.
943 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000944 unsigned a = GrColorUnpackA(paint.fColor);
945 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000946 } else {
947 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000948 }
949}
950
951static void setInsetFan(GrPoint* pts, size_t stride,
952 const GrRect& r, GrScalar dx, GrScalar dy) {
953 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
954}
955
956static const uint16_t gFillAARectIdx[] = {
957 0, 1, 5, 5, 4, 0,
958 1, 2, 6, 6, 5, 1,
959 2, 3, 7, 7, 6, 2,
960 3, 0, 4, 4, 7, 3,
961 4, 5, 6, 6, 7, 4,
962};
963
964int GrContext::aaFillRectIndexCount() const {
965 return GR_ARRAY_COUNT(gFillAARectIdx);
966}
967
968GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
969 if (NULL == fAAFillRectIndexBuffer) {
970 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
971 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000972 if (NULL != fAAFillRectIndexBuffer) {
973 #if GR_DEBUG
974 bool updated =
975 #endif
976 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
977 sizeof(gFillAARectIdx));
978 GR_DEBUGASSERT(updated);
979 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000980 }
981 return fAAFillRectIndexBuffer;
982}
983
984static const uint16_t gStrokeAARectIdx[] = {
985 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
986 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
987 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
988 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
989
990 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
991 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
992 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
993 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
994
995 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
996 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
997 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
998 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
999};
1000
1001int GrContext::aaStrokeRectIndexCount() const {
1002 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1003}
1004
1005GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1006 if (NULL == fAAStrokeRectIndexBuffer) {
1007 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1008 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001009 if (NULL != fAAStrokeRectIndexBuffer) {
1010 #if GR_DEBUG
1011 bool updated =
1012 #endif
1013 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1014 sizeof(gStrokeAARectIdx));
1015 GR_DEBUGASSERT(updated);
1016 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001017 }
1018 return fAAStrokeRectIndexBuffer;
1019}
1020
1021void GrContext::fillAARect(GrDrawTarget* target,
1022 const GrPaint& paint,
1023 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001024 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1025 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001026
1027 size_t vsize = GrDrawTarget::VertexSize(layout);
1028
1029 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001030 if (!geo.succeeded()) {
1031 GrPrintf("Failed to get space for vertices!\n");
1032 return;
1033 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001034 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1035 if (NULL == indexBuffer) {
1036 GrPrintf("Failed to create index buffer!\n");
1037 return;
1038 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001039
1040 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1041
1042 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1043 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1044
1045 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1046 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1047
1048 verts += sizeof(GrPoint);
1049 for (int i = 0; i < 4; ++i) {
1050 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1051 }
1052
1053 GrColor innerColor = getColorForMesh(paint);
1054 verts += 4 * vsize;
1055 for (int i = 0; i < 4; ++i) {
1056 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1057 }
1058
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001059 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001060
1061 target->drawIndexed(kTriangles_PrimitiveType, 0,
1062 0, 8, this->aaFillRectIndexCount());
1063}
1064
1065void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1066 const GrRect& devRect, const GrVec& devStrokeSize) {
1067 const GrScalar& dx = devStrokeSize.fX;
1068 const GrScalar& dy = devStrokeSize.fY;
1069 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1070 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1071
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001072 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1073 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001074
1075 GrScalar spare;
1076 {
1077 GrScalar w = devRect.width() - dx;
1078 GrScalar h = devRect.height() - dy;
1079 spare = GrMin(w, h);
1080 }
1081
1082 if (spare <= 0) {
1083 GrRect r(devRect);
1084 r.inset(-rx, -ry);
1085 fillAARect(target, paint, r);
1086 return;
1087 }
1088
1089 size_t vsize = GrDrawTarget::VertexSize(layout);
1090
1091 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001092 if (!geo.succeeded()) {
1093 GrPrintf("Failed to get space for vertices!\n");
1094 return;
1095 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001096 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1097 if (NULL == indexBuffer) {
1098 GrPrintf("Failed to create index buffer!\n");
1099 return;
1100 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001101
1102 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1103
1104 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1105 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1106 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1107 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1108
1109 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1110 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1111 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1112 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1113
1114 verts += sizeof(GrPoint);
1115 for (int i = 0; i < 4; ++i) {
1116 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1117 }
1118
1119 GrColor innerColor = getColorForMesh(paint);
1120 verts += 4 * vsize;
1121 for (int i = 0; i < 8; ++i) {
1122 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1123 }
1124
1125 verts += 8 * vsize;
1126 for (int i = 0; i < 8; ++i) {
1127 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1128 }
1129
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001130 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001131 target->drawIndexed(kTriangles_PrimitiveType,
1132 0, 0, 16, aaStrokeRectIndexCount());
1133}
1134
reed@google.com20efde72011-05-09 17:00:02 +00001135/**
1136 * Returns true if the rects edges are integer-aligned.
1137 */
1138static bool isIRect(const GrRect& r) {
1139 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1140 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1141}
1142
bsalomon@google.com205d4602011-04-25 12:43:45 +00001143static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001144 const GrRect& rect,
1145 GrScalar width,
1146 const GrMatrix* matrix,
1147 GrMatrix* combinedMatrix,
1148 GrRect* devRect) {
1149 // we use a simple alpha ramp to do aa on axis-aligned rects
1150 // do AA with alpha ramp if the caller requested AA, the rect
1151 // will be axis-aligned,the render target is not
1152 // multisampled, and the rect won't land on integer coords.
1153
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001154 if (!target->isAntialiasState()) {
1155 return false;
1156 }
1157
1158 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001159 return false;
1160 }
1161
1162 if (target->getRenderTarget()->isMultisampled()) {
1163 return false;
1164 }
1165
bsalomon@google.com471d4712011-08-23 15:45:25 +00001166 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001167 return false;
1168 }
1169
1170 if (!target->getViewMatrix().preservesAxisAlignment()) {
1171 return false;
1172 }
1173
1174 if (NULL != matrix &&
1175 !matrix->preservesAxisAlignment()) {
1176 return false;
1177 }
1178
1179 *combinedMatrix = target->getViewMatrix();
1180 if (NULL != matrix) {
1181 combinedMatrix->preConcat(*matrix);
1182 GrAssert(combinedMatrix->preservesAxisAlignment());
1183 }
1184
1185 combinedMatrix->mapRect(devRect, rect);
1186 devRect->sort();
1187
1188 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001189 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001190 } else {
1191 return true;
1192 }
1193}
1194
bsalomon@google.com27847de2011-02-22 20:59:41 +00001195void GrContext::drawRect(const GrPaint& paint,
1196 const GrRect& rect,
1197 GrScalar width,
1198 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001199 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001200
1201 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001202 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001203
bsalomon@google.com205d4602011-04-25 12:43:45 +00001204 GrRect devRect = rect;
1205 GrMatrix combinedMatrix;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001206 bool doAA = apply_aa_to_rect(target, rect, width, matrix,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001207 &combinedMatrix, &devRect);
1208
1209 if (doAA) {
1210 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001211 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001212 GrMatrix inv;
1213 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001214 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001215 }
1216 }
1217 target->setViewMatrix(GrMatrix::I());
1218 if (width >= 0) {
1219 GrVec strokeSize;;
1220 if (width > 0) {
1221 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001222 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001223 strokeSize.setAbs(strokeSize);
1224 } else {
1225 strokeSize.set(GR_Scalar1, GR_Scalar1);
1226 }
1227 strokeAARect(target, paint, devRect, strokeSize);
1228 } else {
1229 fillAARect(target, paint, devRect);
1230 }
1231 return;
1232 }
1233
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234 if (width >= 0) {
1235 // TODO: consider making static vertex buffers for these cases.
1236 // Hairline could be done by just adding closing vertex to
1237 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001238 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1239
bsalomon@google.com27847de2011-02-22 20:59:41 +00001240 static const int worstCaseVertCount = 10;
1241 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1242
1243 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001244 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001245 return;
1246 }
1247
1248 GrPrimitiveType primType;
1249 int vertCount;
1250 GrPoint* vertex = geo.positions();
1251
1252 if (width > 0) {
1253 vertCount = 10;
1254 primType = kTriangleStrip_PrimitiveType;
1255 setStrokeRectStrip(vertex, rect, width);
1256 } else {
1257 // hairline
1258 vertCount = 5;
1259 primType = kLineStrip_PrimitiveType;
1260 vertex[0].set(rect.fLeft, rect.fTop);
1261 vertex[1].set(rect.fRight, rect.fTop);
1262 vertex[2].set(rect.fRight, rect.fBottom);
1263 vertex[3].set(rect.fLeft, rect.fBottom);
1264 vertex[4].set(rect.fLeft, rect.fTop);
1265 }
1266
1267 GrDrawTarget::AutoViewMatrixRestore avmr;
1268 if (NULL != matrix) {
1269 avmr.set(target);
1270 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001271 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001272 }
1273
1274 target->drawNonIndexed(primType, 0, vertCount);
1275 } else {
1276 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001277 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001278 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1279 if (NULL == sqVB) {
1280 GrPrintf("Failed to create static rect vb.\n");
1281 return;
1282 }
1283 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001284 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1285 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001286 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001287 0, rect.height(), rect.fTop,
1288 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001289
1290 if (NULL != matrix) {
1291 m.postConcat(*matrix);
1292 }
1293
1294 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001295 target->preConcatSamplerMatrices(stageMask, m);
1296
bsalomon@google.com27847de2011-02-22 20:59:41 +00001297 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1298 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001299 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300 #endif
1301 }
1302}
1303
1304void GrContext::drawRectToRect(const GrPaint& paint,
1305 const GrRect& dstRect,
1306 const GrRect& srcRect,
1307 const GrMatrix* dstMatrix,
1308 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001309 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001310
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001311 // srcRect refers to paint's first texture
1312 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001313 drawRect(paint, dstRect, -1, dstMatrix);
1314 return;
1315 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001316
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1318
1319#if GR_STATIC_RECT_VB
1320 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001321
1322 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001323 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1324
1325 GrMatrix m;
1326
1327 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1328 0, dstRect.height(), dstRect.fTop,
1329 0, 0, GrMatrix::I()[8]);
1330 if (NULL != dstMatrix) {
1331 m.postConcat(*dstMatrix);
1332 }
1333 target->preConcatViewMatrix(m);
1334
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001335 // srcRect refers to first stage
1336 int otherStageMask = paint.getActiveStageMask() &
1337 (~(1 << GrPaint::kFirstTextureStage));
1338 if (otherStageMask) {
1339 target->preConcatSamplerMatrices(otherStageMask, m);
1340 }
1341
bsalomon@google.com27847de2011-02-22 20:59:41 +00001342 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1343 0, srcRect.height(), srcRect.fTop,
1344 0, 0, GrMatrix::I()[8]);
1345 if (NULL != srcMatrix) {
1346 m.postConcat(*srcMatrix);
1347 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001348 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001349
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001350 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1351 if (NULL == sqVB) {
1352 GrPrintf("Failed to create static rect vb.\n");
1353 return;
1354 }
1355 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001356 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1357#else
1358
1359 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001360#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001361 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001362#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001363 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1364#endif
1365
1366 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1367 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1368 srcRects[0] = &srcRect;
1369 srcMatrices[0] = srcMatrix;
1370
1371 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1372#endif
1373}
1374
1375void GrContext::drawVertices(const GrPaint& paint,
1376 GrPrimitiveType primitiveType,
1377 int vertexCount,
1378 const GrPoint positions[],
1379 const GrPoint texCoords[],
1380 const GrColor colors[],
1381 const uint16_t indices[],
1382 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001383 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001384
1385 GrDrawTarget::AutoReleaseGeometry geo;
1386
1387 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1388
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001389 bool hasTexCoords[GrPaint::kTotalStages] = {
1390 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1391 0 // remaining stages use positions
1392 };
1393
1394 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395
1396 if (NULL != colors) {
1397 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001399 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001400
1401 if (sizeof(GrPoint) != vertexSize) {
1402 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001403 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001404 return;
1405 }
1406 int texOffsets[GrDrawTarget::kMaxTexCoords];
1407 int colorOffset;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001408 int edgeOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001409 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1410 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001411 &colorOffset,
1412 &edgeOffset);
1413 GrAssert(-1 == edgeOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001414 void* curVertex = geo.vertices();
1415
1416 for (int i = 0; i < vertexCount; ++i) {
1417 *((GrPoint*)curVertex) = positions[i];
1418
1419 if (texOffsets[0] > 0) {
1420 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1421 }
1422 if (colorOffset > 0) {
1423 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1424 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001425 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001426 }
1427 } else {
1428 target->setVertexSourceToArray(layout, positions, vertexCount);
1429 }
1430
bsalomon@google.com91958362011-06-13 17:58:13 +00001431 // we don't currently apply offscreen AA to this path. Need improved
1432 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001433
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001434 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001435 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001436 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001437 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001438 target->drawNonIndexed(primitiveType, 0, vertexCount);
1439 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001440}
1441
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001442///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001443
reed@google.com07f3ee12011-05-16 17:21:57 +00001444void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1445 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001446
bsalomon@google.com27847de2011-02-22 20:59:41 +00001447 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001448
1449 // An Assumption here is that path renderer would use some form of tweaking
1450 // the src color (either the input alpha or in the frag shader) to implement
1451 // aa. If we have some future driver-mojo path AA that can do the right
1452 // thing WRT to the blend then we'll need some query on the PR.
1453 if (disable_coverage_aa_for_blend(target)) {
1454 target->disableState(GrDrawTarget::kAntialias_StateBit);
1455 }
1456
bsalomon@google.com30085192011-08-19 15:42:31 +00001457 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1458 if (NULL == pr) {
1459 GrPrintf("Unable to find path renderer compatible with path.\n");
1460 return;
1461 }
1462
bsalomon@google.comee435122011-07-01 14:57:55 +00001463 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1464 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001465
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001466 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001467 this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001468
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001469 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001470
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001471 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001472 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1473 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001474 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001475 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001476 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001477 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001478 return;
1479 }
1480 }
reed@google.com70c136e2011-06-03 19:51:26 +00001481
reed@google.com07f3ee12011-05-16 17:21:57 +00001482 GrRect pathBounds = path.getBounds();
1483 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001484 if (NULL != translate) {
1485 pathBounds.offset(*translate);
1486 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001487 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001488 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001489 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001490 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001491 return;
1492 }
1493 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001494 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001495 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1496 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001497 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1498 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1499 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001500 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001501 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1502 }
1503 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001504 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001505 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001506 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1507 GrRect rect;
1508 if (clipIBounds.fTop < bound.fTop) {
1509 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1510 clipIBounds.fRight, bound.fTop);
1511 target->drawSimpleRect(rect, NULL, stageMask);
1512 }
1513 if (clipIBounds.fLeft < bound.fLeft) {
1514 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1515 bound.fLeft, bound.fBottom);
1516 target->drawSimpleRect(rect, NULL, stageMask);
1517 }
1518 if (clipIBounds.fRight > bound.fRight) {
1519 rect.setLTRB(bound.fRight, bound.fTop,
1520 clipIBounds.fRight, bound.fBottom);
1521 target->drawSimpleRect(rect, NULL, stageMask);
1522 }
1523 if (clipIBounds.fBottom > bound.fBottom) {
1524 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1525 clipIBounds.fRight, clipIBounds.fBottom);
1526 target->drawSimpleRect(rect, NULL, stageMask);
1527 }
1528 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001529 return;
1530 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001531 }
1532 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001533}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001534
bsalomon@google.com27847de2011-02-22 20:59:41 +00001535////////////////////////////////////////////////////////////////////////////////
1536
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001537bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001538 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001539}
1540
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001541void GrContext::flush(int flagsBitfield) {
1542 if (kDiscard_FlushBit & flagsBitfield) {
1543 fDrawBuffer->reset();
1544 } else {
1545 flushDrawBuffer();
1546 }
1547
1548 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001549 fGpu->forceRenderTargetFlush();
1550 }
1551}
1552
1553void GrContext::flushText() {
1554 if (kText_DrawCategory == fLastDrawCategory) {
1555 flushDrawBuffer();
1556 }
1557}
1558
1559void GrContext::flushDrawBuffer() {
1560#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001561 if (fDrawBuffer) {
1562 fDrawBuffer->playback(fGpu);
1563 fDrawBuffer->reset();
1564 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001565#endif
1566}
1567
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001568bool GrContext::readTexturePixels(GrTexture* texture,
1569 int left, int top, int width, int height,
1570 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001571 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001572
1573 // TODO: code read pixels for textures that aren't rendertargets
1574
1575 this->flush();
1576 GrRenderTarget* target = texture->asRenderTarget();
1577 if (NULL != target) {
1578 return fGpu->readPixels(target,
1579 left, top, width, height,
1580 config, buffer);
1581 } else {
1582 return false;
1583 }
1584}
1585
1586bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1587 int left, int top, int width, int height,
1588 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001589 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001590 uint32_t flushFlags = 0;
1591 if (NULL == target) {
1592 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1593 }
1594
1595 this->flush(flushFlags);
1596 return fGpu->readPixels(target,
1597 left, top, width, height,
1598 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001599}
1600
1601void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001602 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001603 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001604 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001605
1606 // TODO: when underlying api has a direct way to do this we should use it
1607 // (e.g. glDrawPixels on desktop GL).
1608
bsalomon@google.com5c638652011-07-18 19:31:59 +00001609 this->flush(true);
1610
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001611 const GrTextureDesc desc = {
1612 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001613 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001614 GrAutoScratchTexture ast(this, desc);
1615 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001616 if (NULL == texture) {
1617 return;
1618 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001619 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001620
bsalomon@google.com27847de2011-02-22 20:59:41 +00001621 GrDrawTarget::AutoStateRestore asr(fGpu);
1622
1623 GrMatrix matrix;
1624 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1625 fGpu->setViewMatrix(matrix);
1626
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001627 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001628 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1629 fGpu->setAlpha(0xFF);
1630 fGpu->setBlendFunc(kOne_BlendCoeff,
1631 kZero_BlendCoeff);
1632 fGpu->setTexture(0, texture);
1633
1634 GrSamplerState sampler;
1635 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001636 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001637 sampler.setMatrix(matrix);
1638 fGpu->setSamplerState(0, sampler);
1639
1640 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1641 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001642 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001643 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1644 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001645 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001646 return;
1647 }
1648 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1649 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1650}
1651////////////////////////////////////////////////////////////////////////////////
1652
1653void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001654
1655 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1656 int s = i + GrPaint::kFirstTextureStage;
1657 target->setTexture(s, paint.getTexture(i));
1658 target->setSamplerState(s, *paint.getTextureSampler(i));
1659 }
1660
1661 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1662
1663 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1664 int s = i + GrPaint::kFirstMaskStage;
1665 target->setTexture(s, paint.getMask(i));
1666 target->setSamplerState(s, *paint.getMaskSampler(i));
1667 }
1668
bsalomon@google.com27847de2011-02-22 20:59:41 +00001669 target->setColor(paint.fColor);
1670
1671 if (paint.fDither) {
1672 target->enableState(GrDrawTarget::kDither_StateBit);
1673 } else {
1674 target->disableState(GrDrawTarget::kDither_StateBit);
1675 }
1676 if (paint.fAntiAlias) {
1677 target->enableState(GrDrawTarget::kAntialias_StateBit);
1678 } else {
1679 target->disableState(GrDrawTarget::kAntialias_StateBit);
1680 }
1681 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001682 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001683
1684 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1685 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1686 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001687}
1688
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001689GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001690 DrawCategory category) {
1691 if (category != fLastDrawCategory) {
1692 flushDrawBuffer();
1693 fLastDrawCategory = category;
1694 }
1695 SetPaint(paint, fGpu);
1696 GrDrawTarget* target = fGpu;
1697 switch (category) {
1698 case kText_DrawCategory:
1699#if DEFER_TEXT_RENDERING
1700 target = fDrawBuffer;
1701 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1702#else
1703 target = fGpu;
1704#endif
1705 break;
1706 case kUnbuffered_DrawCategory:
1707 target = fGpu;
1708 break;
1709 case kBuffered_DrawCategory:
1710 target = fDrawBuffer;
1711 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1712 break;
1713 }
1714 return target;
1715}
1716
bsalomon@google.com30085192011-08-19 15:42:31 +00001717GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1718 const GrPath& path,
1719 GrPathFill fill) {
1720 if (NULL == fPathRendererChain) {
1721 fPathRendererChain =
1722 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1723 }
1724 return fPathRendererChain->getPathRenderer(target, path, fill);
1725}
1726
bsalomon@google.com27847de2011-02-22 20:59:41 +00001727////////////////////////////////////////////////////////////////////////////////
1728
bsalomon@google.com27847de2011-02-22 20:59:41 +00001729void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001730 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001731 fGpu->setRenderTarget(target);
1732}
1733
1734GrRenderTarget* GrContext::getRenderTarget() {
1735 return fGpu->getRenderTarget();
1736}
1737
1738const GrRenderTarget* GrContext::getRenderTarget() const {
1739 return fGpu->getRenderTarget();
1740}
1741
1742const GrMatrix& GrContext::getMatrix() const {
1743 return fGpu->getViewMatrix();
1744}
1745
1746void GrContext::setMatrix(const GrMatrix& m) {
1747 fGpu->setViewMatrix(m);
1748}
1749
1750void GrContext::concatMatrix(const GrMatrix& m) const {
1751 fGpu->preConcatViewMatrix(m);
1752}
1753
1754static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1755 intptr_t mask = 1 << shift;
1756 if (pred) {
1757 bits |= mask;
1758 } else {
1759 bits &= ~mask;
1760 }
1761 return bits;
1762}
1763
1764void GrContext::resetStats() {
1765 fGpu->resetStats();
1766}
1767
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001768const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001769 return fGpu->getStats();
1770}
1771
1772void GrContext::printStats() const {
1773 fGpu->printStats();
1774}
1775
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001776GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001777 fGpu = gpu;
1778 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001779 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001780
bsalomon@google.com30085192011-08-19 15:42:31 +00001781 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001782
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001783 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1784 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001785 fFontCache = new GrFontCache(fGpu);
1786
1787 fLastDrawCategory = kUnbuffered_DrawCategory;
1788
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001789 fDrawBuffer = NULL;
1790 fDrawBufferVBAllocPool = NULL;
1791 fDrawBufferIBAllocPool = NULL;
1792
bsalomon@google.com205d4602011-04-25 12:43:45 +00001793 fAAFillRectIndexBuffer = NULL;
1794 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001795
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001796 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1797 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001798 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1799 }
1800 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001801
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001802 this->setupDrawBuffer();
1803}
1804
1805void GrContext::setupDrawBuffer() {
1806
1807 GrAssert(NULL == fDrawBuffer);
1808 GrAssert(NULL == fDrawBufferVBAllocPool);
1809 GrAssert(NULL == fDrawBufferIBAllocPool);
1810
bsalomon@google.com27847de2011-02-22 20:59:41 +00001811#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001812 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001813 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001814 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1815 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001816 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001817 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001818 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001819 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1820
bsalomon@google.com471d4712011-08-23 15:45:25 +00001821 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1822 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001823 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001824#endif
1825
1826#if BATCH_RECT_TO_RECT
1827 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1828#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001829}
1830
bsalomon@google.com27847de2011-02-22 20:59:41 +00001831GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1832 GrDrawTarget* target;
1833#if DEFER_TEXT_RENDERING
1834 target = prepareToDraw(paint, kText_DrawCategory);
1835#else
1836 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1837#endif
1838 SetPaint(paint, target);
1839 return target;
1840}
1841
1842const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1843 return fGpu->getQuadIndexBuffer();
1844}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001845
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001846void GrContext::convolveInX(GrTexture* texture,
1847 const SkRect& rect,
1848 const float* kernel,
1849 int kernelWidth) {
1850 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1851 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1852}
1853
1854void GrContext::convolveInY(GrTexture* texture,
1855 const SkRect& rect,
1856 const float* kernel,
1857 int kernelWidth) {
1858 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1859 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1860}
1861
1862void GrContext::convolve(GrTexture* texture,
1863 const SkRect& rect,
1864 float imageIncrement[2],
1865 const float* kernel,
1866 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001867 GrDrawTarget::AutoStateRestore asr(fGpu);
1868 GrMatrix sampleM;
1869 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1870 GrSamplerState::kClamp_WrapMode,
1871 GrSamplerState::kConvolution_Filter);
1872 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001873 sampleM.setScale(GR_Scalar1 / texture->width(),
1874 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001875 sampler.setMatrix(sampleM);
1876 fGpu->setSamplerState(0, sampler);
1877 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001878 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001879 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001880 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1881}