blob: e0c7b5559f769b6466c7fea8aa5ebc9e747a7d29 [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.com27847de2011-02-22 20:59:41 +00001448 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001449
1450 // An Assumption here is that path renderer would use some form of tweaking
1451 // the src color (either the input alpha or in the frag shader) to implement
1452 // aa. If we have some future driver-mojo path AA that can do the right
1453 // thing WRT to the blend then we'll need some query on the PR.
1454 if (disable_coverage_aa_for_blend(target)) {
1455 target->disableState(GrDrawTarget::kAntialias_StateBit);
1456 }
1457
bsalomon@google.com30085192011-08-19 15:42:31 +00001458 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1459 if (NULL == pr) {
1460 GrPrintf("Unable to find path renderer compatible with path.\n");
1461 return;
1462 }
1463
bsalomon@google.comee435122011-07-01 14:57:55 +00001464 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1465 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001467 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001468 this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001469
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001470 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001471
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001472 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001473 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1474 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001475 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001476 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001477 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001478 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001479 return;
1480 }
1481 }
reed@google.com70c136e2011-06-03 19:51:26 +00001482
reed@google.com07f3ee12011-05-16 17:21:57 +00001483 GrRect pathBounds = path.getBounds();
1484 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001485 if (NULL != translate) {
1486 pathBounds.offset(*translate);
1487 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001488 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001489 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001490 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001491 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001492 return;
1493 }
1494 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001495 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001496 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1497 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001498 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1499 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1500 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001501 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001502 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1503 }
1504 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001505 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001506 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001507 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1508 GrRect rect;
1509 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001510 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1511 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001512 target->drawSimpleRect(rect, NULL, stageMask);
1513 }
1514 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001515 rect.iset(clipIBounds.fLeft, bound.fTop,
1516 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001517 target->drawSimpleRect(rect, NULL, stageMask);
1518 }
1519 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001520 rect.iset(bound.fRight, bound.fTop,
1521 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001522 target->drawSimpleRect(rect, NULL, stageMask);
1523 }
1524 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001525 rect.iset(clipIBounds.fLeft, bound.fBottom,
1526 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001527 target->drawSimpleRect(rect, NULL, stageMask);
1528 }
1529 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001530 return;
1531 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001532 }
1533 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001534}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001535
bsalomon@google.com27847de2011-02-22 20:59:41 +00001536////////////////////////////////////////////////////////////////////////////////
1537
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001538bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001539 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001540}
1541
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001542void GrContext::flush(int flagsBitfield) {
1543 if (kDiscard_FlushBit & flagsBitfield) {
1544 fDrawBuffer->reset();
1545 } else {
1546 flushDrawBuffer();
1547 }
1548
1549 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001550 fGpu->forceRenderTargetFlush();
1551 }
1552}
1553
1554void GrContext::flushText() {
1555 if (kText_DrawCategory == fLastDrawCategory) {
1556 flushDrawBuffer();
1557 }
1558}
1559
1560void GrContext::flushDrawBuffer() {
1561#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001562 if (fDrawBuffer) {
1563 fDrawBuffer->playback(fGpu);
1564 fDrawBuffer->reset();
1565 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001566#endif
1567}
1568
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001569bool GrContext::readTexturePixels(GrTexture* texture,
1570 int left, int top, int width, int height,
1571 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001572 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001573
1574 // TODO: code read pixels for textures that aren't rendertargets
1575
1576 this->flush();
1577 GrRenderTarget* target = texture->asRenderTarget();
1578 if (NULL != target) {
1579 return fGpu->readPixels(target,
1580 left, top, width, height,
1581 config, buffer);
1582 } else {
1583 return false;
1584 }
1585}
1586
1587bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1588 int left, int top, int width, int height,
1589 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001590 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001591 uint32_t flushFlags = 0;
1592 if (NULL == target) {
1593 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1594 }
1595
1596 this->flush(flushFlags);
1597 return fGpu->readPixels(target,
1598 left, top, width, height,
1599 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001600}
1601
1602void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001603 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001604 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001605 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001606
1607 // TODO: when underlying api has a direct way to do this we should use it
1608 // (e.g. glDrawPixels on desktop GL).
1609
bsalomon@google.com5c638652011-07-18 19:31:59 +00001610 this->flush(true);
1611
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001612 const GrTextureDesc desc = {
1613 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001615 GrAutoScratchTexture ast(this, desc);
1616 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001617 if (NULL == texture) {
1618 return;
1619 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001620 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001621
bsalomon@google.com27847de2011-02-22 20:59:41 +00001622 GrDrawTarget::AutoStateRestore asr(fGpu);
1623
1624 GrMatrix matrix;
1625 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1626 fGpu->setViewMatrix(matrix);
1627
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001628 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001629 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1630 fGpu->setAlpha(0xFF);
1631 fGpu->setBlendFunc(kOne_BlendCoeff,
1632 kZero_BlendCoeff);
1633 fGpu->setTexture(0, texture);
1634
1635 GrSamplerState sampler;
1636 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001637 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001638 sampler.setMatrix(matrix);
1639 fGpu->setSamplerState(0, sampler);
1640
1641 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1642 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001643 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001644 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1645 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001646 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001647 return;
1648 }
1649 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1650 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1651}
1652////////////////////////////////////////////////////////////////////////////////
1653
1654void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001655
1656 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1657 int s = i + GrPaint::kFirstTextureStage;
1658 target->setTexture(s, paint.getTexture(i));
1659 target->setSamplerState(s, *paint.getTextureSampler(i));
1660 }
1661
1662 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1663
1664 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1665 int s = i + GrPaint::kFirstMaskStage;
1666 target->setTexture(s, paint.getMask(i));
1667 target->setSamplerState(s, *paint.getMaskSampler(i));
1668 }
1669
bsalomon@google.com27847de2011-02-22 20:59:41 +00001670 target->setColor(paint.fColor);
1671
1672 if (paint.fDither) {
1673 target->enableState(GrDrawTarget::kDither_StateBit);
1674 } else {
1675 target->disableState(GrDrawTarget::kDither_StateBit);
1676 }
1677 if (paint.fAntiAlias) {
1678 target->enableState(GrDrawTarget::kAntialias_StateBit);
1679 } else {
1680 target->disableState(GrDrawTarget::kAntialias_StateBit);
1681 }
1682 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001683 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001684
1685 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1686 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1687 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001688}
1689
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001690GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001691 DrawCategory category) {
1692 if (category != fLastDrawCategory) {
1693 flushDrawBuffer();
1694 fLastDrawCategory = category;
1695 }
1696 SetPaint(paint, fGpu);
1697 GrDrawTarget* target = fGpu;
1698 switch (category) {
1699 case kText_DrawCategory:
1700#if DEFER_TEXT_RENDERING
1701 target = fDrawBuffer;
1702 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1703#else
1704 target = fGpu;
1705#endif
1706 break;
1707 case kUnbuffered_DrawCategory:
1708 target = fGpu;
1709 break;
1710 case kBuffered_DrawCategory:
1711 target = fDrawBuffer;
1712 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1713 break;
1714 }
1715 return target;
1716}
1717
bsalomon@google.com30085192011-08-19 15:42:31 +00001718GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1719 const GrPath& path,
1720 GrPathFill fill) {
1721 if (NULL == fPathRendererChain) {
1722 fPathRendererChain =
1723 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1724 }
1725 return fPathRendererChain->getPathRenderer(target, path, fill);
1726}
1727
bsalomon@google.com27847de2011-02-22 20:59:41 +00001728////////////////////////////////////////////////////////////////////////////////
1729
bsalomon@google.com27847de2011-02-22 20:59:41 +00001730void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001731 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001732 fGpu->setRenderTarget(target);
1733}
1734
1735GrRenderTarget* GrContext::getRenderTarget() {
1736 return fGpu->getRenderTarget();
1737}
1738
1739const GrRenderTarget* GrContext::getRenderTarget() const {
1740 return fGpu->getRenderTarget();
1741}
1742
1743const GrMatrix& GrContext::getMatrix() const {
1744 return fGpu->getViewMatrix();
1745}
1746
1747void GrContext::setMatrix(const GrMatrix& m) {
1748 fGpu->setViewMatrix(m);
1749}
1750
1751void GrContext::concatMatrix(const GrMatrix& m) const {
1752 fGpu->preConcatViewMatrix(m);
1753}
1754
1755static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1756 intptr_t mask = 1 << shift;
1757 if (pred) {
1758 bits |= mask;
1759 } else {
1760 bits &= ~mask;
1761 }
1762 return bits;
1763}
1764
1765void GrContext::resetStats() {
1766 fGpu->resetStats();
1767}
1768
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001769const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001770 return fGpu->getStats();
1771}
1772
1773void GrContext::printStats() const {
1774 fGpu->printStats();
1775}
1776
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001777GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001778 fGpu = gpu;
1779 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001780 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001781
bsalomon@google.com30085192011-08-19 15:42:31 +00001782 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001783
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001784 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1785 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001786 fFontCache = new GrFontCache(fGpu);
1787
1788 fLastDrawCategory = kUnbuffered_DrawCategory;
1789
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001790 fDrawBuffer = NULL;
1791 fDrawBufferVBAllocPool = NULL;
1792 fDrawBufferIBAllocPool = NULL;
1793
bsalomon@google.com205d4602011-04-25 12:43:45 +00001794 fAAFillRectIndexBuffer = NULL;
1795 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001796
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001797 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1798 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001799 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1800 }
1801 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001802
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001803 this->setupDrawBuffer();
1804}
1805
1806void GrContext::setupDrawBuffer() {
1807
1808 GrAssert(NULL == fDrawBuffer);
1809 GrAssert(NULL == fDrawBufferVBAllocPool);
1810 GrAssert(NULL == fDrawBufferIBAllocPool);
1811
bsalomon@google.com27847de2011-02-22 20:59:41 +00001812#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001813 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001814 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001815 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1816 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001817 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001818 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001819 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001820 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1821
bsalomon@google.com471d4712011-08-23 15:45:25 +00001822 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1823 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001824 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001825#endif
1826
1827#if BATCH_RECT_TO_RECT
1828 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1829#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001830}
1831
bsalomon@google.com27847de2011-02-22 20:59:41 +00001832GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1833 GrDrawTarget* target;
1834#if DEFER_TEXT_RENDERING
1835 target = prepareToDraw(paint, kText_DrawCategory);
1836#else
1837 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1838#endif
1839 SetPaint(paint, target);
1840 return target;
1841}
1842
1843const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1844 return fGpu->getQuadIndexBuffer();
1845}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001846
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001847void GrContext::convolveInX(GrTexture* texture,
1848 const SkRect& rect,
1849 const float* kernel,
1850 int kernelWidth) {
1851 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1852 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1853}
1854
1855void GrContext::convolveInY(GrTexture* texture,
1856 const SkRect& rect,
1857 const float* kernel,
1858 int kernelWidth) {
1859 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1860 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1861}
1862
1863void GrContext::convolve(GrTexture* texture,
1864 const SkRect& rect,
1865 float imageIncrement[2],
1866 const float* kernel,
1867 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001868 GrDrawTarget::AutoStateRestore asr(fGpu);
1869 GrMatrix sampleM;
1870 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1871 GrSamplerState::kClamp_WrapMode,
1872 GrSamplerState::kConvolution_Filter);
1873 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001874 sampleM.setScale(GR_Scalar1 / texture->width(),
1875 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001876 sampler.setMatrix(sampleM);
1877 fGpu->setSamplerState(0, sampler);
1878 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001879 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001880 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001881 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1882}