blob: 9c3f298f11cc4535f12c4e9721448f53afa1eedd [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"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000021#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000022
bsalomon@google.com91958362011-06-13 17:58:13 +000023// Using MSAA seems to be slower for some yet unknown reason.
24#define PREFER_MSAA_OFFSCREEN_AA 0
25#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000026
bsalomon@google.com27847de2011-02-22 20:59:41 +000027#define DEFER_TEXT_RENDERING 1
28
29#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
30
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000031static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
32static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000033
34static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
35static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
36
37// We are currently only batching Text and drawRectToRect, both
38// of which use the quad index buffer.
39static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
40static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
41
bsalomon@google.com05ef5102011-05-02 21:14:59 +000042GrContext* GrContext::Create(GrEngine engine,
43 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000044 GrContext* ctx = NULL;
45 GrGpu* fGpu = GrGpu::Create(engine, context3D);
46 if (NULL != fGpu) {
47 ctx = new GrContext(fGpu);
48 fGpu->unref();
49 }
50 return ctx;
51}
52
53GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000054 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000055}
56
57GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000058 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000059 delete fTextureCache;
60 delete fFontCache;
61 delete fDrawBuffer;
62 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000063 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000064
bsalomon@google.com205d4602011-04-25 12:43:45 +000065 GrSafeUnref(fAAFillRectIndexBuffer);
66 GrSafeUnref(fAAStrokeRectIndexBuffer);
67 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000068 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000069}
70
bsalomon@google.com8fe72472011-03-30 21:26:44 +000071void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000072 contextDestroyed();
73 this->setupDrawBuffer();
74}
75
76void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000077 // abandon first to so destructors
78 // don't try to free the resources in the API.
79 fGpu->abandonResources();
80
bsalomon@google.com30085192011-08-19 15:42:31 +000081 // a path renderer may be holding onto resources that
82 // are now unusable
83 GrSafeSetNull(fPathRendererChain);
84
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBuffer;
86 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000087
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBufferVBAllocPool;
89 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferIBAllocPool;
92 fDrawBufferIBAllocPool = NULL;
93
bsalomon@google.com205d4602011-04-25 12:43:45 +000094 GrSafeSetNull(fAAFillRectIndexBuffer);
95 GrSafeSetNull(fAAStrokeRectIndexBuffer);
96
bsalomon@google.com8fe72472011-03-30 21:26:44 +000097 fTextureCache->removeAll();
98 fFontCache->freeAll();
99 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100}
101
102void GrContext::resetContext() {
103 fGpu->markContextDirty();
104}
105
106void GrContext::freeGpuResources() {
107 this->flush();
108 fTextureCache->removeAll();
109 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000110 // a path renderer may be holding onto resources
111 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000112}
113
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000114////////////////////////////////////////////////////////////////////////////////
115
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000116int GrContext::PaintStageVertexLayoutBits(
117 const GrPaint& paint,
118 const bool hasTexCoords[GrPaint::kTotalStages]) {
119 int stageMask = paint.getActiveStageMask();
120 int layout = 0;
121 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
122 if ((1 << i) & stageMask) {
123 if (NULL != hasTexCoords && hasTexCoords[i]) {
124 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
125 } else {
126 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
127 }
128 }
129 }
130 return layout;
131}
132
133
134////////////////////////////////////////////////////////////////////////////////
135
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000136enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000137 // flags for textures
138 kNPOTBit = 0x1,
139 kFilterBit = 0x2,
140 kScratchBit = 0x4,
141
142 // resource type
143 kTextureBit = 0x8,
144 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000145};
146
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000147GrTexture* GrContext::TextureCacheEntry::texture() const {
148 if (NULL == fEntry) {
149 return NULL;
150 } else {
151 return (GrTexture*) fEntry->resource();
152 }
153}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000154
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000155namespace {
156// returns true if this is a "special" texture because of gpu NPOT limitations
157bool gen_texture_key_values(const GrGpu* gpu,
158 const GrSamplerState& sampler,
159 GrContext::TextureKey clientKey,
160 int width,
161 int height,
162 bool scratch,
163 uint32_t v[4]) {
164 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
165 // we assume we only need 16 bits of width and height
166 // assert that texture creation will fail anyway if this assumption
167 // would cause key collisions.
168 GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
169 v[0] = clientKey & 0xffffffffUL;
170 v[1] = (clientKey >> 32) & 0xffffffffUL;
171 v[2] = width | (height << 16);
172
173 v[3] = 0;
174 if (!gpu->npotTextureTileSupport()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000175 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
176
177 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
178 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
179
180 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000181 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000182 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000183 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184 }
185 }
186 }
187
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 if (scratch) {
189 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000190 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000192 v[3] |= kTextureBit;
193
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194 return v[3] & kNPOTBit;
195}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000196
197// we should never have more than one stencil buffer with same combo of
198// (width,height,samplecount)
199void gen_stencil_key_values(int width, int height,
200 int sampleCnt, uint32_t v[4]) {
201 v[0] = width;
202 v[1] = height;
203 v[2] = sampleCnt;
204 v[3] = kStencilBufferBit;
205}
206
207void gen_stencil_key_values(const GrStencilBuffer* sb,
208 uint32_t v[4]) {
209 gen_stencil_key_values(sb->width(), sb->height(),
210 sb->numSamples(), v);
211}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000212}
213
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000214GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
215 int width,
216 int height,
217 const GrSamplerState& sampler) {
218 uint32_t v[4];
219 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
220 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000221 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
222 GrResourceCache::kNested_LockType));
223}
224
225GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
226 uint32_t v[4];
227 gen_stencil_key_values(sb, v);
228 GrResourceKey resourceKey(v);
229 return fTextureCache->createAndLock(resourceKey, sb);
230}
231
232GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
233 int sampleCnt) {
234 uint32_t v[4];
235 gen_stencil_key_values(width, height, sampleCnt, v);
236 GrResourceKey resourceKey(v);
237 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
238 GrResourceCache::kSingle_LockType);
239 if (NULL != entry) {
240 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
241 return sb;
242 } else {
243 return NULL;
244 }
245}
246
247void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
248 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000249}
250
251static void stretchImage(void* dst,
252 int dstW,
253 int dstH,
254 void* src,
255 int srcW,
256 int srcH,
257 int bpp) {
258 GrFixed dx = (srcW << 16) / dstW;
259 GrFixed dy = (srcH << 16) / dstH;
260
261 GrFixed y = dy >> 1;
262
263 int dstXLimit = dstW*bpp;
264 for (int j = 0; j < dstH; ++j) {
265 GrFixed x = dx >> 1;
266 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
267 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
268 for (int i = 0; i < dstXLimit; i += bpp) {
269 memcpy((uint8_t*) dstRow + i,
270 (uint8_t*) srcRow + (x>>16)*bpp,
271 bpp);
272 x += dx;
273 }
274 y += dy;
275 }
276}
277
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000278GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000279 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000280 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000281 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000282 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000283
284#if GR_DUMP_TEXTURE_UPLOAD
285 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
286#endif
287
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000288 TextureCacheEntry entry;
289 uint32_t v[4];
290 bool special = gen_texture_key_values(fGpu, sampler, key,
291 desc.fWidth, desc.fHeight, false, v);
292 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000293
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000294 if (special) {
295 TextureCacheEntry clampEntry =
296 findAndLockTexture(key, desc.fWidth, desc.fHeight,
297 GrSamplerState::ClampNoFilter());
298
299 if (NULL == clampEntry.texture()) {
300 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000301 GrSamplerState::ClampNoFilter(),
302 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000303 GrAssert(NULL != clampEntry.texture());
304 if (NULL == clampEntry.texture()) {
305 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000306 }
307 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000308 GrTextureDesc rtDesc = desc;
309 rtDesc.fFlags = rtDesc.fFlags |
310 kRenderTarget_GrTextureFlagBit |
311 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000312 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
313 fGpu->minRenderTargetWidth()));
314 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
315 fGpu->minRenderTargetHeight()));
316
317 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
318
319 if (NULL != texture) {
320 GrDrawTarget::AutoStateRestore asr(fGpu);
321 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000322 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000323 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000324 fGpu->setViewMatrix(GrMatrix::I());
325 fGpu->setAlpha(0xff);
326 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
327 fGpu->disableState(GrDrawTarget::kDither_StateBit |
328 GrDrawTarget::kClip_StateBit |
329 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000330 GrSamplerState::Filter filter;
331 // if filtering is not desired then we want to ensure all
332 // texels in the resampled image are copies of texels from
333 // the original.
334 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
335 filter = GrSamplerState::kNearest_Filter;
336 } else {
337 filter = GrSamplerState::kBilinear_Filter;
338 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000339 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
340 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000341 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000342 fGpu->setSamplerState(0, stretchSampler);
343
344 static const GrVertexLayout layout =
345 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
346 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
347
348 if (arg.succeeded()) {
349 GrPoint* verts = (GrPoint*) arg.vertices();
350 verts[0].setIRectFan(0, 0,
351 texture->width(),
352 texture->height(),
353 2*sizeof(GrPoint));
354 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
355 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
356 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000357 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000358 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000359 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000360 } else {
361 // TODO: Our CPU stretch doesn't filter. But we create separate
362 // stretched textures when the sampler state is either filtered or
363 // not. Either implement filtered stretch blit on CPU or just create
364 // one when FBO case fails.
365
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000366 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000367 // no longer need to clamp at min RT size.
368 rtDesc.fWidth = GrNextPow2(desc.fWidth);
369 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000370 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000371 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000372 rtDesc.fWidth *
373 rtDesc.fHeight);
374 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
375 srcData, desc.fWidth, desc.fHeight, bpp);
376
377 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
378
379 GrTexture* texture = fGpu->createTexture(rtDesc,
380 stretchedPixels.get(),
381 stretchedRowBytes);
382 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000383 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000384 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000385 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000386
387 } else {
388 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
389 if (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 }
392 }
393 return entry;
394}
395
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000396namespace {
397inline void gen_scratch_tex_key_values(const GrGpu* gpu,
398 const GrTextureDesc& desc,
399 uint32_t v[4]) {
400 // Instead of a client-provided key of the texture contents
401 // we create a key of from the descriptor.
402 GrContext::TextureKey descKey = desc.fAALevel |
403 (desc.fFlags << 8) |
404 ((uint64_t) desc.fFormat << 32);
405 // this code path isn't friendly to tiling with NPOT restricitons
406 // We just pass ClampNoFilter()
407 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
408 desc.fWidth, desc.fHeight, true, v);
409}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000410}
411
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412GrContext::TextureCacheEntry GrContext::lockScratchTexture(
413 const GrTextureDesc& inDesc,
414 ScratchTexMatch match) {
415
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000416 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000417 if (kExact_ScratchTexMatch != match) {
418 // bin by pow2 with a reasonable min
419 static const int MIN_SIZE = 256;
420 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
421 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
422 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000423
424 uint32_t p0 = desc.fFormat;
425 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
426
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000428 int origWidth = desc.fWidth;
429 int origHeight = desc.fHeight;
430 bool doubledW = false;
431 bool doubledH = false;
432
433 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 uint32_t v[4];
435 gen_scratch_tex_key_values(fGpu, desc, v);
436 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000437 entry = fTextureCache->findAndLock(key,
438 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000439 // if we miss, relax the fit of the flags...
440 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000442 break;
443 }
444 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
445 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
446 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
447 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
448 } else if (!doubledW) {
449 desc.fFlags = inDesc.fFlags;
450 desc.fWidth *= 2;
451 doubledW = true;
452 } else if (!doubledH) {
453 desc.fFlags = inDesc.fFlags;
454 desc.fWidth = origWidth;
455 desc.fHeight *= 2;
456 doubledH = true;
457 } else {
458 break;
459 }
460
461 } while (true);
462
463 if (NULL == entry) {
464 desc.fFlags = inDesc.fFlags;
465 desc.fWidth = origWidth;
466 desc.fHeight = origHeight;
467 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
468 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000469 uint32_t v[4];
470 gen_scratch_tex_key_values(fGpu, desc, v);
471 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000472 entry = fTextureCache->createAndLock(key, texture);
473 }
474 }
475
476 // If the caller gives us the same desc/sampler twice we don't want
477 // to return the same texture the second time (unless it was previously
478 // released). So we detach the entry from the cache and reattach at release.
479 if (NULL != entry) {
480 fTextureCache->detach(entry);
481 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000482 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000483}
484
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485void GrContext::unlockTexture(TextureCacheEntry entry) {
486 // If this is a scratch texture we detached it from the cache
487 // while it was locked (to avoid two callers simultaneously getting
488 // the same texture).
489 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
490 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000491 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000492 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000493 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000494}
495
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000496GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000497 void* srcData,
498 size_t rowBytes) {
499 return fGpu->createTexture(desc, srcData, rowBytes);
500}
501
502void GrContext::getTextureCacheLimits(int* maxTextures,
503 size_t* maxTextureBytes) const {
504 fTextureCache->getLimits(maxTextures, maxTextureBytes);
505}
506
507void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
508 fTextureCache->setLimits(maxTextures, maxTextureBytes);
509}
510
bsalomon@google.com91958362011-06-13 17:58:13 +0000511int GrContext::getMaxTextureSize() const {
512 return fGpu->maxTextureSize();
513}
514
515int GrContext::getMaxRenderTargetSize() const {
516 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000517}
518
519///////////////////////////////////////////////////////////////////////////////
520
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000521GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
522 // validate flags here so that GrGpu subclasses don't have to check
523 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
524 0 != desc.fRenderTargetFlags) {
525 return NULL;
526 }
bsalomon@google.com47370822011-08-02 15:29:38 +0000527#if !GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000528 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
529 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
530 return NULL;
531 }
532 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
533 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
534 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
535 return NULL;
536 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000537#else
538 if (desc.fSampleCnt &&
539 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
540 return NULL;
541 }
542 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
543 desc.fSampleCnt &&
544 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
545 return NULL;
546 }
547#endif
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000548 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000549}
550
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000551///////////////////////////////////////////////////////////////////////////////
552
bsalomon@google.com27847de2011-02-22 20:59:41 +0000553bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
554 int width, int height) {
555 if (!fGpu->supports8BitPalette()) {
556 return false;
557 }
558
559
560 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
561
562 if (!isPow2) {
563 if (!fGpu->npotTextureSupport()) {
564 return false;
565 }
566
567 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
568 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
569 if (tiled && !fGpu->npotTextureTileSupport()) {
570 return false;
571 }
572 }
573 return true;
574}
575
576////////////////////////////////////////////////////////////////////////////////
577
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000578const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
579
bsalomon@google.com27847de2011-02-22 20:59:41 +0000580void GrContext::setClip(const GrClip& clip) {
581 fGpu->setClip(clip);
582 fGpu->enableState(GrDrawTarget::kClip_StateBit);
583}
584
585void GrContext::setClip(const GrIRect& rect) {
586 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000587 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588 fGpu->setClip(clip);
589}
590
591////////////////////////////////////////////////////////////////////////////////
592
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000593void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000594 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000595 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596}
597
598void GrContext::drawPaint(const GrPaint& paint) {
599 // set rect to be big enough to fill the space, but not super-huge, so we
600 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000601 GrRect r;
602 r.setLTRB(0, 0,
603 GrIntToScalar(getRenderTarget()->width()),
604 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000605 GrMatrix inverse;
606 if (fGpu->getViewInverse(&inverse)) {
607 inverse.mapRect(&r);
608 } else {
609 GrPrintf("---- fGpu->getViewInverse failed\n");
610 }
611 this->drawRect(paint, r);
612}
613
bsalomon@google.com205d4602011-04-25 12:43:45 +0000614////////////////////////////////////////////////////////////////////////////////
615
bsalomon@google.com91958362011-06-13 17:58:13 +0000616struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000617 enum Downsample {
618 k4x4TwoPass_Downsample,
619 k4x4SinglePass_Downsample,
620 kFSAA_Downsample
621 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000622 int fTileSizeX;
623 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000624 int fTileCountX;
625 int fTileCountY;
626 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000627 GrAutoScratchTexture fOffscreen0;
628 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000629 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000630 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000631};
632
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000633bool GrContext::doOffscreenAA(GrDrawTarget* target,
634 const GrPaint& paint,
635 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000636#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000637 return false;
638#else
639 if (!paint.fAntiAlias) {
640 return false;
641 }
642 if (isLines && fGpu->supportsAALines()) {
643 return false;
644 }
645 if (target->getRenderTarget()->isMultisampled()) {
646 return false;
647 }
648 // we have to be sure that the blend equation is expressible
649 // as simple src / dst coeffecients when the source
650 // is already modulated by the coverage fraction.
651 // We could use dual-source blending to get the correct per-pixel
652 // dst coeffecient for the remaining cases.
653 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
654 kOne_BlendCoeff != paint.fDstBlendCoeff &&
655 kISA_BlendCoeff != paint.fDstBlendCoeff) {
656 return false;
657 }
658 return true;
659#endif
660}
661
bsalomon@google.com91958362011-06-13 17:58:13 +0000662bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000663 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000664 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000665 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000666 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000667
668 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000669
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000670 GrAssert(NULL == record->fOffscreen0.texture());
671 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000672 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000673
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000674 int boundW = boundRect.width();
675 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000676
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000677 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000678
679 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
680 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
681
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000682 if (requireStencil) {
683 desc.fFlags = kRenderTarget_GrTextureFlagBit;
684 } else {
685 desc.fFlags = kRenderTarget_GrTextureFlagBit |
686 kNoStencil_GrTextureFlagBit;
687 }
688
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000689 desc.fFormat = kRGBA_8888_GrPixelConfig;
690
bsalomon@google.com91958362011-06-13 17:58:13 +0000691 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000692 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000693 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000694 desc.fAALevel = kMed_GrAALevel;
695 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000696 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
697 OffscreenRecord::k4x4SinglePass_Downsample :
698 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000699 record->fScale = OFFSCREEN_SSAA_SCALE;
700 // both downsample paths assume this
701 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000702 desc.fAALevel = kNone_GrAALevel;
703 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000704 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
705 // of simple circles?
706 if (pr) {
707 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
708 }
709
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000710 desc.fWidth *= record->fScale;
711 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000712 record->fOffscreen0.set(this, desc);
713 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000714 return false;
715 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000716 // the approximate lookup might have given us some slop space, might as well
717 // use it when computing the tiles size.
718 // these are scale values, will adjust after considering
719 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000720 record->fTileSizeX = record->fOffscreen0.texture()->width();
721 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000722
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000723 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000724 desc.fWidth /= 2;
725 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000726 record->fOffscreen1.set(this, desc);
727 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000728 return false;
729 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000730 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000731 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000732 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000733 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000734 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000735 record->fTileSizeX /= record->fScale;
736 record->fTileSizeY /= record->fScale;
737
738 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
739 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
740
tomhudson@google.com237a4612011-07-19 15:44:00 +0000741 record->fClip = target->getClip();
742
bsalomon@google.com91958362011-06-13 17:58:13 +0000743 target->saveCurrentDrawState(&record->fSavedState);
744 return true;
745}
746
747void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
748 const GrIRect& boundRect,
749 int tileX, int tileY,
750 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000751
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000752 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000753 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000754
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000755 GrPaint tempPaint;
756 tempPaint.reset();
757 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000758 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000759
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000760 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000761 int left = boundRect.fLeft + tileX * record->fTileSizeX;
762 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000763 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000764 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000765 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000766 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000767 target->postConcatViewMatrix(scaleM);
768
bsalomon@google.com91958362011-06-13 17:58:13 +0000769 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000770 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000771 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000772 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000773 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
774 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000775 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000776#if 0
777 // visualize tile boundaries by setting edges of offscreen to white
778 // and interior to tranparent. black.
779 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000780
bsalomon@google.com91958362011-06-13 17:58:13 +0000781 static const int gOffset = 2;
782 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
783 record->fScale * w - gOffset,
784 record->fScale * h - gOffset);
785 target->clear(&clear2, 0x0);
786#else
787 target->clear(&clear, 0x0);
788#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000789}
790
bsalomon@google.com91958362011-06-13 17:58:13 +0000791void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000792 const GrPaint& paint,
793 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000794 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000796 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000797 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000798 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000799 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000800 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
801 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000802 tileRect.fRight = (tileX == record->fTileCountX-1) ?
803 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000804 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000805 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
806 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000807 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000808
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000809 GrSamplerState::Filter filter;
810 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
811 filter = GrSamplerState::k4x4Downsample_Filter;
812 } else {
813 filter = GrSamplerState::kBilinear_Filter;
814 }
815
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000816 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000817 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000818 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000819
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000820 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000821 int scale;
822
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000823 enum {
824 kOffscreenStage = GrPaint::kTotalStages,
825 };
826
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000827 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000828 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000829 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000830 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000831
832 // Do 2x2 downsample from first to second
833 target->setTexture(kOffscreenStage, src);
834 target->setRenderTarget(dst);
835 target->setViewMatrix(GrMatrix::I());
836 sampleM.setScale(scale * GR_Scalar1 / src->width(),
837 scale * GR_Scalar1 / src->height());
838 sampler.setMatrix(sampleM);
839 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000840 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
841 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000842 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
843
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000844 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000845 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000846 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000847 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000848 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000849 } else {
850 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
851 record->fDownsample);
852 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000853 }
854
bsalomon@google.com91958362011-06-13 17:58:13 +0000855 // setup for draw back to main RT, we use the original
856 // draw state setup by the caller plus an additional coverage
857 // stage to handle the AA resolve. Also, we use an identity
858 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000859 int stageMask = paint.getActiveStageMask();
860
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000861 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000862 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000863
864 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000865 GrMatrix invVM;
866 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000867 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000868 }
869 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000870 // This is important when tiling, otherwise second tile's
871 // pass 1 view matrix will be incorrect.
872 GrDrawTarget::AutoViewMatrixRestore avmr(target);
873
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000874 target->setViewMatrix(GrMatrix::I());
875
876 target->setTexture(kOffscreenStage, src);
877 sampleM.setScale(scale * GR_Scalar1 / src->width(),
878 scale * GR_Scalar1 / src->height());
879 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000880 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000881 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000882 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000883
reed@google.com20efde72011-05-09 17:00:02 +0000884 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000885 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000886 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000887 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000888}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000889
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000890void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
891 GrPathRenderer* pr,
892 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000893 if (pr) {
894 // Counterpart of scale() in prepareForOffscreenAA()
895 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
896 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000897 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000898}
899
900////////////////////////////////////////////////////////////////////////////////
901
bsalomon@google.com27847de2011-02-22 20:59:41 +0000902/* create a triangle strip that strokes the specified triangle. There are 8
903 unique vertices, but we repreat the last 2 to close up. Alternatively we
904 could use an indices array, and then only send 8 verts, but not sure that
905 would be faster.
906 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000907static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000908 GrScalar width) {
909 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000910 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000911
912 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
913 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
914 verts[2].set(rect.fRight - rad, rect.fTop + rad);
915 verts[3].set(rect.fRight + rad, rect.fTop - rad);
916 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
917 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
918 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
919 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
920 verts[8] = verts[0];
921 verts[9] = verts[1];
922}
923
bsalomon@google.com205d4602011-04-25 12:43:45 +0000924static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000925 // FIXME: This was copied from SkGpuDevice, seems like
926 // we should have already smeared a in caller if that
927 // is what is desired.
928 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000929 unsigned a = GrColorUnpackA(paint.fColor);
930 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000931 } else {
932 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000933 }
934}
935
936static void setInsetFan(GrPoint* pts, size_t stride,
937 const GrRect& r, GrScalar dx, GrScalar dy) {
938 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
939}
940
941static const uint16_t gFillAARectIdx[] = {
942 0, 1, 5, 5, 4, 0,
943 1, 2, 6, 6, 5, 1,
944 2, 3, 7, 7, 6, 2,
945 3, 0, 4, 4, 7, 3,
946 4, 5, 6, 6, 7, 4,
947};
948
949int GrContext::aaFillRectIndexCount() const {
950 return GR_ARRAY_COUNT(gFillAARectIdx);
951}
952
953GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
954 if (NULL == fAAFillRectIndexBuffer) {
955 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
956 false);
957 GrAssert(NULL != fAAFillRectIndexBuffer);
958#if GR_DEBUG
959 bool updated =
960#endif
961 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
962 sizeof(gFillAARectIdx));
963 GR_DEBUGASSERT(updated);
964 }
965 return fAAFillRectIndexBuffer;
966}
967
968static const uint16_t gStrokeAARectIdx[] = {
969 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
970 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
971 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
972 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
973
974 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
975 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
976 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
977 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
978
979 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
980 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
981 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
982 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
983};
984
985int GrContext::aaStrokeRectIndexCount() const {
986 return GR_ARRAY_COUNT(gStrokeAARectIdx);
987}
988
989GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
990 if (NULL == fAAStrokeRectIndexBuffer) {
991 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
992 false);
993 GrAssert(NULL != fAAStrokeRectIndexBuffer);
994#if GR_DEBUG
995 bool updated =
996#endif
997 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
998 sizeof(gStrokeAARectIdx));
999 GR_DEBUGASSERT(updated);
1000 }
1001 return fAAStrokeRectIndexBuffer;
1002}
1003
1004void GrContext::fillAARect(GrDrawTarget* target,
1005 const GrPaint& paint,
1006 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001007 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1008 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001009
1010 size_t vsize = GrDrawTarget::VertexSize(layout);
1011
1012 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001013 if (!geo.succeeded()) {
1014 GrPrintf("Failed to get space for vertices!\n");
1015 return;
1016 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001017
1018 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1019
1020 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1021 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1022
1023 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1024 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1025
1026 verts += sizeof(GrPoint);
1027 for (int i = 0; i < 4; ++i) {
1028 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1029 }
1030
1031 GrColor innerColor = getColorForMesh(paint);
1032 verts += 4 * vsize;
1033 for (int i = 0; i < 4; ++i) {
1034 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1035 }
1036
1037 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
1038
1039 target->drawIndexed(kTriangles_PrimitiveType, 0,
1040 0, 8, this->aaFillRectIndexCount());
1041}
1042
1043void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1044 const GrRect& devRect, const GrVec& devStrokeSize) {
1045 const GrScalar& dx = devStrokeSize.fX;
1046 const GrScalar& dy = devStrokeSize.fY;
1047 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1048 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1049
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001050 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1051 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001052
1053 GrScalar spare;
1054 {
1055 GrScalar w = devRect.width() - dx;
1056 GrScalar h = devRect.height() - dy;
1057 spare = GrMin(w, h);
1058 }
1059
1060 if (spare <= 0) {
1061 GrRect r(devRect);
1062 r.inset(-rx, -ry);
1063 fillAARect(target, paint, r);
1064 return;
1065 }
1066
1067 size_t vsize = GrDrawTarget::VertexSize(layout);
1068
1069 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001070 if (!geo.succeeded()) {
1071 GrPrintf("Failed to get space for vertices!\n");
1072 return;
1073 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001074
1075 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1076
1077 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1078 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1079 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1080 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1081
1082 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1083 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1084 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1085 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1086
1087 verts += sizeof(GrPoint);
1088 for (int i = 0; i < 4; ++i) {
1089 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1090 }
1091
1092 GrColor innerColor = getColorForMesh(paint);
1093 verts += 4 * vsize;
1094 for (int i = 0; i < 8; ++i) {
1095 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1096 }
1097
1098 verts += 8 * vsize;
1099 for (int i = 0; i < 8; ++i) {
1100 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1101 }
1102
1103 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1104 target->drawIndexed(kTriangles_PrimitiveType,
1105 0, 0, 16, aaStrokeRectIndexCount());
1106}
1107
reed@google.com20efde72011-05-09 17:00:02 +00001108/**
1109 * Returns true if the rects edges are integer-aligned.
1110 */
1111static bool isIRect(const GrRect& r) {
1112 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1113 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1114}
1115
bsalomon@google.com205d4602011-04-25 12:43:45 +00001116static bool apply_aa_to_rect(GrDrawTarget* target,
1117 GrGpu* gpu,
1118 const GrPaint& paint,
1119 const GrRect& rect,
1120 GrScalar width,
1121 const GrMatrix* matrix,
1122 GrMatrix* combinedMatrix,
1123 GrRect* devRect) {
1124 // we use a simple alpha ramp to do aa on axis-aligned rects
1125 // do AA with alpha ramp if the caller requested AA, the rect
1126 // will be axis-aligned,the render target is not
1127 // multisampled, and the rect won't land on integer coords.
1128
1129 if (!paint.fAntiAlias) {
1130 return false;
1131 }
1132
1133 if (target->getRenderTarget()->isMultisampled()) {
1134 return false;
1135 }
1136
1137 if (0 == width && gpu->supportsAALines()) {
1138 return false;
1139 }
1140
1141 if (!target->getViewMatrix().preservesAxisAlignment()) {
1142 return false;
1143 }
1144
1145 if (NULL != matrix &&
1146 !matrix->preservesAxisAlignment()) {
1147 return false;
1148 }
1149
1150 *combinedMatrix = target->getViewMatrix();
1151 if (NULL != matrix) {
1152 combinedMatrix->preConcat(*matrix);
1153 GrAssert(combinedMatrix->preservesAxisAlignment());
1154 }
1155
1156 combinedMatrix->mapRect(devRect, rect);
1157 devRect->sort();
1158
1159 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001160 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001161 } else {
1162 return true;
1163 }
1164}
1165
bsalomon@google.com27847de2011-02-22 20:59:41 +00001166void GrContext::drawRect(const GrPaint& paint,
1167 const GrRect& rect,
1168 GrScalar width,
1169 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001170 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001171
1172 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001173 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001174
bsalomon@google.com205d4602011-04-25 12:43:45 +00001175 GrRect devRect = rect;
1176 GrMatrix combinedMatrix;
1177 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1178 &combinedMatrix, &devRect);
1179
1180 if (doAA) {
1181 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001182 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001183 GrMatrix inv;
1184 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001185 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001186 }
1187 }
1188 target->setViewMatrix(GrMatrix::I());
1189 if (width >= 0) {
1190 GrVec strokeSize;;
1191 if (width > 0) {
1192 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001193 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001194 strokeSize.setAbs(strokeSize);
1195 } else {
1196 strokeSize.set(GR_Scalar1, GR_Scalar1);
1197 }
1198 strokeAARect(target, paint, devRect, strokeSize);
1199 } else {
1200 fillAARect(target, paint, devRect);
1201 }
1202 return;
1203 }
1204
bsalomon@google.com27847de2011-02-22 20:59:41 +00001205 if (width >= 0) {
1206 // TODO: consider making static vertex buffers for these cases.
1207 // Hairline could be done by just adding closing vertex to
1208 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001209 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1210
bsalomon@google.com27847de2011-02-22 20:59:41 +00001211 static const int worstCaseVertCount = 10;
1212 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1213
1214 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001215 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001216 return;
1217 }
1218
1219 GrPrimitiveType primType;
1220 int vertCount;
1221 GrPoint* vertex = geo.positions();
1222
1223 if (width > 0) {
1224 vertCount = 10;
1225 primType = kTriangleStrip_PrimitiveType;
1226 setStrokeRectStrip(vertex, rect, width);
1227 } else {
1228 // hairline
1229 vertCount = 5;
1230 primType = kLineStrip_PrimitiveType;
1231 vertex[0].set(rect.fLeft, rect.fTop);
1232 vertex[1].set(rect.fRight, rect.fTop);
1233 vertex[2].set(rect.fRight, rect.fBottom);
1234 vertex[3].set(rect.fLeft, rect.fBottom);
1235 vertex[4].set(rect.fLeft, rect.fTop);
1236 }
1237
1238 GrDrawTarget::AutoViewMatrixRestore avmr;
1239 if (NULL != matrix) {
1240 avmr.set(target);
1241 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001242 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001243 }
1244
1245 target->drawNonIndexed(primType, 0, vertCount);
1246 } else {
1247 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001248 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001249 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1250 if (NULL == sqVB) {
1251 GrPrintf("Failed to create static rect vb.\n");
1252 return;
1253 }
1254 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1256 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001257 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001258 0, rect.height(), rect.fTop,
1259 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001260
1261 if (NULL != matrix) {
1262 m.postConcat(*matrix);
1263 }
1264
1265 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001266 target->preConcatSamplerMatrices(stageMask, m);
1267
bsalomon@google.com27847de2011-02-22 20:59:41 +00001268 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1269 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001270 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001271 #endif
1272 }
1273}
1274
1275void GrContext::drawRectToRect(const GrPaint& paint,
1276 const GrRect& dstRect,
1277 const GrRect& srcRect,
1278 const GrMatrix* dstMatrix,
1279 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001280 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001281
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001282 // srcRect refers to paint's first texture
1283 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001284 drawRect(paint, dstRect, -1, dstMatrix);
1285 return;
1286 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001287
bsalomon@google.com27847de2011-02-22 20:59:41 +00001288 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1289
1290#if GR_STATIC_RECT_VB
1291 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001292
1293 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001294 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1295
1296 GrMatrix m;
1297
1298 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1299 0, dstRect.height(), dstRect.fTop,
1300 0, 0, GrMatrix::I()[8]);
1301 if (NULL != dstMatrix) {
1302 m.postConcat(*dstMatrix);
1303 }
1304 target->preConcatViewMatrix(m);
1305
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001306 // srcRect refers to first stage
1307 int otherStageMask = paint.getActiveStageMask() &
1308 (~(1 << GrPaint::kFirstTextureStage));
1309 if (otherStageMask) {
1310 target->preConcatSamplerMatrices(otherStageMask, m);
1311 }
1312
bsalomon@google.com27847de2011-02-22 20:59:41 +00001313 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1314 0, srcRect.height(), srcRect.fTop,
1315 0, 0, GrMatrix::I()[8]);
1316 if (NULL != srcMatrix) {
1317 m.postConcat(*srcMatrix);
1318 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001319 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001320
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001321 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1322 if (NULL == sqVB) {
1323 GrPrintf("Failed to create static rect vb.\n");
1324 return;
1325 }
1326 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1328#else
1329
1330 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001331#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001332 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001333#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001334 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1335#endif
1336
1337 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1338 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1339 srcRects[0] = &srcRect;
1340 srcMatrices[0] = srcMatrix;
1341
1342 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1343#endif
1344}
1345
1346void GrContext::drawVertices(const GrPaint& paint,
1347 GrPrimitiveType primitiveType,
1348 int vertexCount,
1349 const GrPoint positions[],
1350 const GrPoint texCoords[],
1351 const GrColor colors[],
1352 const uint16_t indices[],
1353 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001354 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001355
1356 GrDrawTarget::AutoReleaseGeometry geo;
1357
1358 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1359
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001360 bool hasTexCoords[GrPaint::kTotalStages] = {
1361 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1362 0 // remaining stages use positions
1363 };
1364
1365 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001366
1367 if (NULL != colors) {
1368 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001369 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001370 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001371
1372 if (sizeof(GrPoint) != vertexSize) {
1373 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001374 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001375 return;
1376 }
1377 int texOffsets[GrDrawTarget::kMaxTexCoords];
1378 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001379 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1380 texOffsets,
1381 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001382 void* curVertex = geo.vertices();
1383
1384 for (int i = 0; i < vertexCount; ++i) {
1385 *((GrPoint*)curVertex) = positions[i];
1386
1387 if (texOffsets[0] > 0) {
1388 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1389 }
1390 if (colorOffset > 0) {
1391 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1392 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001393 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001394 }
1395 } else {
1396 target->setVertexSourceToArray(layout, positions, vertexCount);
1397 }
1398
bsalomon@google.com91958362011-06-13 17:58:13 +00001399 // we don't currently apply offscreen AA to this path. Need improved
1400 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001401
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001402 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001403 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001404 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001406 target->drawNonIndexed(primitiveType, 0, vertexCount);
1407 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001408}
1409
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001410///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411
reed@google.com07f3ee12011-05-16 17:21:57 +00001412void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1413 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001414
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001416 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1417 if (NULL == pr) {
1418 GrPrintf("Unable to find path renderer compatible with path.\n");
1419 return;
1420 }
1421
bsalomon@google.comee435122011-07-01 14:57:55 +00001422 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1423 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001424
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001425 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001426 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001427
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001428 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001429
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001430 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001431 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1432 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001433 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001434 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001435 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001436 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001437 return;
1438 }
1439 }
reed@google.com70c136e2011-06-03 19:51:26 +00001440
reed@google.com07f3ee12011-05-16 17:21:57 +00001441 GrRect pathBounds = path.getBounds();
1442 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001443 if (NULL != translate) {
1444 pathBounds.offset(*translate);
1445 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001446 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001447 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001448 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001449 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001450 return;
1451 }
1452 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001453 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001454 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1455 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001456 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1457 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1458 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001459 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001460 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1461 }
1462 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001463 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001464 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001465 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1466 GrRect rect;
1467 if (clipIBounds.fTop < bound.fTop) {
1468 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1469 clipIBounds.fRight, bound.fTop);
1470 target->drawSimpleRect(rect, NULL, stageMask);
1471 }
1472 if (clipIBounds.fLeft < bound.fLeft) {
1473 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1474 bound.fLeft, bound.fBottom);
1475 target->drawSimpleRect(rect, NULL, stageMask);
1476 }
1477 if (clipIBounds.fRight > bound.fRight) {
1478 rect.setLTRB(bound.fRight, bound.fTop,
1479 clipIBounds.fRight, bound.fBottom);
1480 target->drawSimpleRect(rect, NULL, stageMask);
1481 }
1482 if (clipIBounds.fBottom > bound.fBottom) {
1483 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1484 clipIBounds.fRight, clipIBounds.fBottom);
1485 target->drawSimpleRect(rect, NULL, stageMask);
1486 }
1487 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001488 return;
1489 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001490 }
1491 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001492}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001493
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494////////////////////////////////////////////////////////////////////////////////
1495
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001496void GrContext::flush(int flagsBitfield) {
1497 if (kDiscard_FlushBit & flagsBitfield) {
1498 fDrawBuffer->reset();
1499 } else {
1500 flushDrawBuffer();
1501 }
1502
1503 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001504 fGpu->forceRenderTargetFlush();
1505 }
1506}
1507
1508void GrContext::flushText() {
1509 if (kText_DrawCategory == fLastDrawCategory) {
1510 flushDrawBuffer();
1511 }
1512}
1513
1514void GrContext::flushDrawBuffer() {
1515#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001516 if (fDrawBuffer) {
1517 fDrawBuffer->playback(fGpu);
1518 fDrawBuffer->reset();
1519 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001520#endif
1521}
1522
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001523bool GrContext::readTexturePixels(GrTexture* texture,
1524 int left, int top, int width, int height,
1525 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001526 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001527
1528 // TODO: code read pixels for textures that aren't rendertargets
1529
1530 this->flush();
1531 GrRenderTarget* target = texture->asRenderTarget();
1532 if (NULL != target) {
1533 return fGpu->readPixels(target,
1534 left, top, width, height,
1535 config, buffer);
1536 } else {
1537 return false;
1538 }
1539}
1540
1541bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1542 int left, int top, int width, int height,
1543 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001544 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001545 uint32_t flushFlags = 0;
1546 if (NULL == target) {
1547 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1548 }
1549
1550 this->flush(flushFlags);
1551 return fGpu->readPixels(target,
1552 left, top, width, height,
1553 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001554}
1555
1556void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001557 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001558 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001559 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001560
1561 // TODO: when underlying api has a direct way to do this we should use it
1562 // (e.g. glDrawPixels on desktop GL).
1563
bsalomon@google.com5c638652011-07-18 19:31:59 +00001564 this->flush(true);
1565
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001566 const GrTextureDesc desc = {
1567 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001568 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001569 GrAutoScratchTexture ast(this, desc);
1570 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001571 if (NULL == texture) {
1572 return;
1573 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001574 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001575
bsalomon@google.com27847de2011-02-22 20:59:41 +00001576 GrDrawTarget::AutoStateRestore asr(fGpu);
1577
1578 GrMatrix matrix;
1579 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1580 fGpu->setViewMatrix(matrix);
1581
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001582 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001583 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1584 fGpu->setAlpha(0xFF);
1585 fGpu->setBlendFunc(kOne_BlendCoeff,
1586 kZero_BlendCoeff);
1587 fGpu->setTexture(0, texture);
1588
1589 GrSamplerState sampler;
1590 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001591 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001592 sampler.setMatrix(matrix);
1593 fGpu->setSamplerState(0, sampler);
1594
1595 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1596 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001597 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001598 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1599 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001600 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001601 return;
1602 }
1603 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1604 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1605}
1606////////////////////////////////////////////////////////////////////////////////
1607
1608void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001609
1610 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1611 int s = i + GrPaint::kFirstTextureStage;
1612 target->setTexture(s, paint.getTexture(i));
1613 target->setSamplerState(s, *paint.getTextureSampler(i));
1614 }
1615
1616 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1617
1618 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1619 int s = i + GrPaint::kFirstMaskStage;
1620 target->setTexture(s, paint.getMask(i));
1621 target->setSamplerState(s, *paint.getMaskSampler(i));
1622 }
1623
bsalomon@google.com27847de2011-02-22 20:59:41 +00001624 target->setColor(paint.fColor);
1625
1626 if (paint.fDither) {
1627 target->enableState(GrDrawTarget::kDither_StateBit);
1628 } else {
1629 target->disableState(GrDrawTarget::kDither_StateBit);
1630 }
1631 if (paint.fAntiAlias) {
1632 target->enableState(GrDrawTarget::kAntialias_StateBit);
1633 } else {
1634 target->disableState(GrDrawTarget::kAntialias_StateBit);
1635 }
1636 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001637 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001638}
1639
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001640GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001641 DrawCategory category) {
1642 if (category != fLastDrawCategory) {
1643 flushDrawBuffer();
1644 fLastDrawCategory = category;
1645 }
1646 SetPaint(paint, fGpu);
1647 GrDrawTarget* target = fGpu;
1648 switch (category) {
1649 case kText_DrawCategory:
1650#if DEFER_TEXT_RENDERING
1651 target = fDrawBuffer;
1652 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1653#else
1654 target = fGpu;
1655#endif
1656 break;
1657 case kUnbuffered_DrawCategory:
1658 target = fGpu;
1659 break;
1660 case kBuffered_DrawCategory:
1661 target = fDrawBuffer;
1662 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1663 break;
1664 }
1665 return target;
1666}
1667
bsalomon@google.com30085192011-08-19 15:42:31 +00001668GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1669 const GrPath& path,
1670 GrPathFill fill) {
1671 if (NULL == fPathRendererChain) {
1672 fPathRendererChain =
1673 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1674 }
1675 return fPathRendererChain->getPathRenderer(target, path, fill);
1676}
1677
bsalomon@google.com27847de2011-02-22 20:59:41 +00001678////////////////////////////////////////////////////////////////////////////////
1679
bsalomon@google.com27847de2011-02-22 20:59:41 +00001680void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001681 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001682 fGpu->setRenderTarget(target);
1683}
1684
1685GrRenderTarget* GrContext::getRenderTarget() {
1686 return fGpu->getRenderTarget();
1687}
1688
1689const GrRenderTarget* GrContext::getRenderTarget() const {
1690 return fGpu->getRenderTarget();
1691}
1692
1693const GrMatrix& GrContext::getMatrix() const {
1694 return fGpu->getViewMatrix();
1695}
1696
1697void GrContext::setMatrix(const GrMatrix& m) {
1698 fGpu->setViewMatrix(m);
1699}
1700
1701void GrContext::concatMatrix(const GrMatrix& m) const {
1702 fGpu->preConcatViewMatrix(m);
1703}
1704
1705static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1706 intptr_t mask = 1 << shift;
1707 if (pred) {
1708 bits |= mask;
1709 } else {
1710 bits &= ~mask;
1711 }
1712 return bits;
1713}
1714
1715void GrContext::resetStats() {
1716 fGpu->resetStats();
1717}
1718
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001719const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001720 return fGpu->getStats();
1721}
1722
1723void GrContext::printStats() const {
1724 fGpu->printStats();
1725}
1726
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001727GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001728 fGpu = gpu;
1729 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001730 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001731
bsalomon@google.com30085192011-08-19 15:42:31 +00001732 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001733
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001734 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1735 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001736 fFontCache = new GrFontCache(fGpu);
1737
1738 fLastDrawCategory = kUnbuffered_DrawCategory;
1739
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001740 fDrawBuffer = NULL;
1741 fDrawBufferVBAllocPool = NULL;
1742 fDrawBufferIBAllocPool = NULL;
1743
bsalomon@google.com205d4602011-04-25 12:43:45 +00001744 fAAFillRectIndexBuffer = NULL;
1745 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001746
1747 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1748 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1749 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1750 }
1751 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001752
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001753 this->setupDrawBuffer();
1754}
1755
1756void GrContext::setupDrawBuffer() {
1757
1758 GrAssert(NULL == fDrawBuffer);
1759 GrAssert(NULL == fDrawBufferVBAllocPool);
1760 GrAssert(NULL == fDrawBufferIBAllocPool);
1761
bsalomon@google.com27847de2011-02-22 20:59:41 +00001762#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001763 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001764 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001765 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1766 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001767 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001768 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001769 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001770 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1771
1772 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1773 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001774#endif
1775
1776#if BATCH_RECT_TO_RECT
1777 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1778#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001779}
1780
bsalomon@google.com27847de2011-02-22 20:59:41 +00001781GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1782 GrDrawTarget* target;
1783#if DEFER_TEXT_RENDERING
1784 target = prepareToDraw(paint, kText_DrawCategory);
1785#else
1786 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1787#endif
1788 SetPaint(paint, target);
1789 return target;
1790}
1791
1792const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1793 return fGpu->getQuadIndexBuffer();
1794}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001795
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001796void GrContext::convolveInX(GrTexture* texture,
1797 const SkRect& rect,
1798 const float* kernel,
1799 int kernelWidth) {
1800 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1801 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1802}
1803
1804void GrContext::convolveInY(GrTexture* texture,
1805 const SkRect& rect,
1806 const float* kernel,
1807 int kernelWidth) {
1808 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1809 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1810}
1811
1812void GrContext::convolve(GrTexture* texture,
1813 const SkRect& rect,
1814 float imageIncrement[2],
1815 const float* kernel,
1816 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001817 GrDrawTarget::AutoStateRestore asr(fGpu);
1818 GrMatrix sampleM;
1819 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1820 GrSamplerState::kClamp_WrapMode,
1821 GrSamplerState::kConvolution_Filter);
1822 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001823 sampleM.setScale(GR_Scalar1 / texture->width(),
1824 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001825 sampler.setMatrix(sampleM);
1826 fGpu->setSamplerState(0, sampler);
1827 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001828 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001829 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001830 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1831}