blob: b3e902d798ea92f4ed6f3ec57f9dd6b88865b104 [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.com583a1e32011-08-17 13:42:46 +000064 GrSafeUnref(fDefaultPathRenderer);
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000065 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000066 GrSafeUnref(fAAFillRectIndexBuffer);
67 GrSafeUnref(fAAStrokeRectIndexBuffer);
68 fGpu->unref();
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.com8fe72472011-03-30 21:26:44 +000081 delete fDrawBuffer;
82 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000083
bsalomon@google.com8fe72472011-03-30 21:26:44 +000084 delete fDrawBufferVBAllocPool;
85 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000086
bsalomon@google.com8fe72472011-03-30 21:26:44 +000087 delete fDrawBufferIBAllocPool;
88 fDrawBufferIBAllocPool = NULL;
89
bsalomon@google.com205d4602011-04-25 12:43:45 +000090 GrSafeSetNull(fAAFillRectIndexBuffer);
91 GrSafeSetNull(fAAStrokeRectIndexBuffer);
92
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 fTextureCache->removeAll();
94 fFontCache->freeAll();
95 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +000096}
97
98void GrContext::resetContext() {
99 fGpu->markContextDirty();
100}
101
102void GrContext::freeGpuResources() {
103 this->flush();
104 fTextureCache->removeAll();
105 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000106}
107
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000108////////////////////////////////////////////////////////////////////////////////
109
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000110int GrContext::PaintStageVertexLayoutBits(
111 const GrPaint& paint,
112 const bool hasTexCoords[GrPaint::kTotalStages]) {
113 int stageMask = paint.getActiveStageMask();
114 int layout = 0;
115 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
116 if ((1 << i) & stageMask) {
117 if (NULL != hasTexCoords && hasTexCoords[i]) {
118 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
119 } else {
120 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
121 }
122 }
123 }
124 return layout;
125}
126
127
128////////////////////////////////////////////////////////////////////////////////
129
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000130enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000131 // flags for textures
132 kNPOTBit = 0x1,
133 kFilterBit = 0x2,
134 kScratchBit = 0x4,
135
136 // resource type
137 kTextureBit = 0x8,
138 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000139};
140
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000141GrTexture* GrContext::TextureCacheEntry::texture() const {
142 if (NULL == fEntry) {
143 return NULL;
144 } else {
145 return (GrTexture*) fEntry->resource();
146 }
147}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000148
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000149namespace {
150// returns true if this is a "special" texture because of gpu NPOT limitations
151bool gen_texture_key_values(const GrGpu* gpu,
152 const GrSamplerState& sampler,
153 GrContext::TextureKey clientKey,
154 int width,
155 int height,
156 bool scratch,
157 uint32_t v[4]) {
158 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
159 // we assume we only need 16 bits of width and height
160 // assert that texture creation will fail anyway if this assumption
161 // would cause key collisions.
162 GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
163 v[0] = clientKey & 0xffffffffUL;
164 v[1] = (clientKey >> 32) & 0xffffffffUL;
165 v[2] = width | (height << 16);
166
167 v[3] = 0;
168 if (!gpu->npotTextureTileSupport()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000169 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
170
171 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
172 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
173
174 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000175 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000176 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000177 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000178 }
179 }
180 }
181
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000182 if (scratch) {
183 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000185
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000186 v[3] |= kTextureBit;
187
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 return v[3] & kNPOTBit;
189}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000190
191// we should never have more than one stencil buffer with same combo of
192// (width,height,samplecount)
193void gen_stencil_key_values(int width, int height,
194 int sampleCnt, uint32_t v[4]) {
195 v[0] = width;
196 v[1] = height;
197 v[2] = sampleCnt;
198 v[3] = kStencilBufferBit;
199}
200
201void gen_stencil_key_values(const GrStencilBuffer* sb,
202 uint32_t v[4]) {
203 gen_stencil_key_values(sb->width(), sb->height(),
204 sb->numSamples(), v);
205}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000206}
207
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000208GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
209 int width,
210 int height,
211 const GrSamplerState& sampler) {
212 uint32_t v[4];
213 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
214 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000215 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
216 GrResourceCache::kNested_LockType));
217}
218
219GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
220 uint32_t v[4];
221 gen_stencil_key_values(sb, v);
222 GrResourceKey resourceKey(v);
223 return fTextureCache->createAndLock(resourceKey, sb);
224}
225
226GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
227 int sampleCnt) {
228 uint32_t v[4];
229 gen_stencil_key_values(width, height, sampleCnt, v);
230 GrResourceKey resourceKey(v);
231 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
232 GrResourceCache::kSingle_LockType);
233 if (NULL != entry) {
234 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
235 return sb;
236 } else {
237 return NULL;
238 }
239}
240
241void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
242 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000243}
244
245static void stretchImage(void* dst,
246 int dstW,
247 int dstH,
248 void* src,
249 int srcW,
250 int srcH,
251 int bpp) {
252 GrFixed dx = (srcW << 16) / dstW;
253 GrFixed dy = (srcH << 16) / dstH;
254
255 GrFixed y = dy >> 1;
256
257 int dstXLimit = dstW*bpp;
258 for (int j = 0; j < dstH; ++j) {
259 GrFixed x = dx >> 1;
260 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
261 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
262 for (int i = 0; i < dstXLimit; i += bpp) {
263 memcpy((uint8_t*) dstRow + i,
264 (uint8_t*) srcRow + (x>>16)*bpp,
265 bpp);
266 x += dx;
267 }
268 y += dy;
269 }
270}
271
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000272GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000273 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000274 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000275 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000276 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000277
278#if GR_DUMP_TEXTURE_UPLOAD
279 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
280#endif
281
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000282 TextureCacheEntry entry;
283 uint32_t v[4];
284 bool special = gen_texture_key_values(fGpu, sampler, key,
285 desc.fWidth, desc.fHeight, false, v);
286 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000287
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000288 if (special) {
289 TextureCacheEntry clampEntry =
290 findAndLockTexture(key, desc.fWidth, desc.fHeight,
291 GrSamplerState::ClampNoFilter());
292
293 if (NULL == clampEntry.texture()) {
294 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000295 GrSamplerState::ClampNoFilter(),
296 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000297 GrAssert(NULL != clampEntry.texture());
298 if (NULL == clampEntry.texture()) {
299 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000300 }
301 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000302 GrTextureDesc rtDesc = desc;
303 rtDesc.fFlags = rtDesc.fFlags |
304 kRenderTarget_GrTextureFlagBit |
305 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000306 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
307 fGpu->minRenderTargetWidth()));
308 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
309 fGpu->minRenderTargetHeight()));
310
311 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
312
313 if (NULL != texture) {
314 GrDrawTarget::AutoStateRestore asr(fGpu);
315 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000316 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000317 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000318 fGpu->setViewMatrix(GrMatrix::I());
319 fGpu->setAlpha(0xff);
320 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
321 fGpu->disableState(GrDrawTarget::kDither_StateBit |
322 GrDrawTarget::kClip_StateBit |
323 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000324 GrSamplerState::Filter filter;
325 // if filtering is not desired then we want to ensure all
326 // texels in the resampled image are copies of texels from
327 // the original.
328 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
329 filter = GrSamplerState::kNearest_Filter;
330 } else {
331 filter = GrSamplerState::kBilinear_Filter;
332 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000333 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
334 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000335 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000336 fGpu->setSamplerState(0, stretchSampler);
337
338 static const GrVertexLayout layout =
339 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
340 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
341
342 if (arg.succeeded()) {
343 GrPoint* verts = (GrPoint*) arg.vertices();
344 verts[0].setIRectFan(0, 0,
345 texture->width(),
346 texture->height(),
347 2*sizeof(GrPoint));
348 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
349 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
350 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000351 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000352 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000353 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000354 } else {
355 // TODO: Our CPU stretch doesn't filter. But we create separate
356 // stretched textures when the sampler state is either filtered or
357 // not. Either implement filtered stretch blit on CPU or just create
358 // one when FBO case fails.
359
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000360 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000361 // no longer need to clamp at min RT size.
362 rtDesc.fWidth = GrNextPow2(desc.fWidth);
363 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000364 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000365 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000366 rtDesc.fWidth *
367 rtDesc.fHeight);
368 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
369 srcData, desc.fWidth, desc.fHeight, bpp);
370
371 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
372
373 GrTexture* texture = fGpu->createTexture(rtDesc,
374 stretchedPixels.get(),
375 stretchedRowBytes);
376 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000377 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000378 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000379 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000380
381 } else {
382 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
383 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000384 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000385 }
386 }
387 return entry;
388}
389
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000390namespace {
391inline void gen_scratch_tex_key_values(const GrGpu* gpu,
392 const GrTextureDesc& desc,
393 uint32_t v[4]) {
394 // Instead of a client-provided key of the texture contents
395 // we create a key of from the descriptor.
396 GrContext::TextureKey descKey = desc.fAALevel |
397 (desc.fFlags << 8) |
398 ((uint64_t) desc.fFormat << 32);
399 // this code path isn't friendly to tiling with NPOT restricitons
400 // We just pass ClampNoFilter()
401 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
402 desc.fWidth, desc.fHeight, true, v);
403}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000404}
405
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000406GrContext::TextureCacheEntry GrContext::lockScratchTexture(
407 const GrTextureDesc& inDesc,
408 ScratchTexMatch match) {
409
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000410 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000411 if (kExact_ScratchTexMatch != match) {
412 // bin by pow2 with a reasonable min
413 static const int MIN_SIZE = 256;
414 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
415 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
416 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000417
418 uint32_t p0 = desc.fFormat;
419 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
420
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000422 int origWidth = desc.fWidth;
423 int origHeight = desc.fHeight;
424 bool doubledW = false;
425 bool doubledH = false;
426
427 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000428 uint32_t v[4];
429 gen_scratch_tex_key_values(fGpu, desc, v);
430 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000431 entry = fTextureCache->findAndLock(key,
432 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000433 // if we miss, relax the fit of the flags...
434 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000435 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000436 break;
437 }
438 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
439 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
440 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
441 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
442 } else if (!doubledW) {
443 desc.fFlags = inDesc.fFlags;
444 desc.fWidth *= 2;
445 doubledW = true;
446 } else if (!doubledH) {
447 desc.fFlags = inDesc.fFlags;
448 desc.fWidth = origWidth;
449 desc.fHeight *= 2;
450 doubledH = true;
451 } else {
452 break;
453 }
454
455 } while (true);
456
457 if (NULL == entry) {
458 desc.fFlags = inDesc.fFlags;
459 desc.fWidth = origWidth;
460 desc.fHeight = origHeight;
461 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
462 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000463 uint32_t v[4];
464 gen_scratch_tex_key_values(fGpu, desc, v);
465 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000466 entry = fTextureCache->createAndLock(key, texture);
467 }
468 }
469
470 // If the caller gives us the same desc/sampler twice we don't want
471 // to return the same texture the second time (unless it was previously
472 // released). So we detach the entry from the cache and reattach at release.
473 if (NULL != entry) {
474 fTextureCache->detach(entry);
475 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000476 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000477}
478
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000479void GrContext::unlockTexture(TextureCacheEntry entry) {
480 // If this is a scratch texture we detached it from the cache
481 // while it was locked (to avoid two callers simultaneously getting
482 // the same texture).
483 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
484 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000485 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000486 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000487 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000488}
489
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000490GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000491 void* srcData,
492 size_t rowBytes) {
493 return fGpu->createTexture(desc, srcData, rowBytes);
494}
495
496void GrContext::getTextureCacheLimits(int* maxTextures,
497 size_t* maxTextureBytes) const {
498 fTextureCache->getLimits(maxTextures, maxTextureBytes);
499}
500
501void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
502 fTextureCache->setLimits(maxTextures, maxTextureBytes);
503}
504
bsalomon@google.com91958362011-06-13 17:58:13 +0000505int GrContext::getMaxTextureSize() const {
506 return fGpu->maxTextureSize();
507}
508
509int GrContext::getMaxRenderTargetSize() const {
510 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000511}
512
513///////////////////////////////////////////////////////////////////////////////
514
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000515GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
516 // validate flags here so that GrGpu subclasses don't have to check
517 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
518 0 != desc.fRenderTargetFlags) {
519 return NULL;
520 }
bsalomon@google.com47370822011-08-02 15:29:38 +0000521#if !GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000522 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
523 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
524 return NULL;
525 }
526 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
527 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
528 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
529 return NULL;
530 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000531#else
532 if (desc.fSampleCnt &&
533 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
534 return NULL;
535 }
536 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
537 desc.fSampleCnt &&
538 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
539 return NULL;
540 }
541#endif
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000542 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000543}
544
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000545GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000546 return fGpu->createRenderTargetFrom3DApiState();
547}
548
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000549///////////////////////////////////////////////////////////////////////////////
550
bsalomon@google.com27847de2011-02-22 20:59:41 +0000551bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
552 int width, int height) {
553 if (!fGpu->supports8BitPalette()) {
554 return false;
555 }
556
557
558 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
559
560 if (!isPow2) {
561 if (!fGpu->npotTextureSupport()) {
562 return false;
563 }
564
565 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
566 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
567 if (tiled && !fGpu->npotTextureTileSupport()) {
568 return false;
569 }
570 }
571 return true;
572}
573
574////////////////////////////////////////////////////////////////////////////////
575
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000576const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
577
bsalomon@google.com27847de2011-02-22 20:59:41 +0000578void GrContext::setClip(const GrClip& clip) {
579 fGpu->setClip(clip);
580 fGpu->enableState(GrDrawTarget::kClip_StateBit);
581}
582
583void GrContext::setClip(const GrIRect& rect) {
584 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000585 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000586 fGpu->setClip(clip);
587}
588
589////////////////////////////////////////////////////////////////////////////////
590
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000591void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000592 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000593 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000594}
595
596void GrContext::drawPaint(const GrPaint& paint) {
597 // set rect to be big enough to fill the space, but not super-huge, so we
598 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000599 GrRect r;
600 r.setLTRB(0, 0,
601 GrIntToScalar(getRenderTarget()->width()),
602 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000603 GrMatrix inverse;
604 if (fGpu->getViewInverse(&inverse)) {
605 inverse.mapRect(&r);
606 } else {
607 GrPrintf("---- fGpu->getViewInverse failed\n");
608 }
609 this->drawRect(paint, r);
610}
611
bsalomon@google.com205d4602011-04-25 12:43:45 +0000612////////////////////////////////////////////////////////////////////////////////
613
bsalomon@google.com91958362011-06-13 17:58:13 +0000614struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000615 enum Downsample {
616 k4x4TwoPass_Downsample,
617 k4x4SinglePass_Downsample,
618 kFSAA_Downsample
619 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000620 int fTileSizeX;
621 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000622 int fTileCountX;
623 int fTileCountY;
624 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000625 GrAutoScratchTexture fOffscreen0;
626 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000627 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000628 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000629};
630
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000631bool GrContext::doOffscreenAA(GrDrawTarget* target,
632 const GrPaint& paint,
633 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000634#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000635 return false;
636#else
637 if (!paint.fAntiAlias) {
638 return false;
639 }
640 if (isLines && fGpu->supportsAALines()) {
641 return false;
642 }
643 if (target->getRenderTarget()->isMultisampled()) {
644 return false;
645 }
646 // we have to be sure that the blend equation is expressible
647 // as simple src / dst coeffecients when the source
648 // is already modulated by the coverage fraction.
649 // We could use dual-source blending to get the correct per-pixel
650 // dst coeffecient for the remaining cases.
651 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
652 kOne_BlendCoeff != paint.fDstBlendCoeff &&
653 kISA_BlendCoeff != paint.fDstBlendCoeff) {
654 return false;
655 }
656 return true;
657#endif
658}
659
bsalomon@google.com91958362011-06-13 17:58:13 +0000660bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000661 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000662 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000663 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000664 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000665
666 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000667
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000668 GrAssert(NULL == record->fOffscreen0.texture());
669 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000670 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000671
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000672 int boundW = boundRect.width();
673 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000674
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000675 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000676
677 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
678 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
679
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000680 if (requireStencil) {
681 desc.fFlags = kRenderTarget_GrTextureFlagBit;
682 } else {
683 desc.fFlags = kRenderTarget_GrTextureFlagBit |
684 kNoStencil_GrTextureFlagBit;
685 }
686
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000687 desc.fFormat = kRGBA_8888_GrPixelConfig;
688
bsalomon@google.com91958362011-06-13 17:58:13 +0000689 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000690 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000691 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000692 desc.fAALevel = kMed_GrAALevel;
693 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000694 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
695 OffscreenRecord::k4x4SinglePass_Downsample :
696 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000697 record->fScale = OFFSCREEN_SSAA_SCALE;
698 // both downsample paths assume this
699 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000700 desc.fAALevel = kNone_GrAALevel;
701 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000702 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
703 // of simple circles?
704 if (pr) {
705 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
706 }
707
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000708 desc.fWidth *= record->fScale;
709 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000710 record->fOffscreen0.set(this, desc);
711 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000712 return false;
713 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000714 // the approximate lookup might have given us some slop space, might as well
715 // use it when computing the tiles size.
716 // these are scale values, will adjust after considering
717 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000718 record->fTileSizeX = record->fOffscreen0.texture()->width();
719 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000720
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000721 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000722 desc.fWidth /= 2;
723 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000724 record->fOffscreen1.set(this, desc);
725 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000726 return false;
727 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000728 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000729 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000730 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000731 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000732 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000733 record->fTileSizeX /= record->fScale;
734 record->fTileSizeY /= record->fScale;
735
736 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
737 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
738
tomhudson@google.com237a4612011-07-19 15:44:00 +0000739 record->fClip = target->getClip();
740
bsalomon@google.com91958362011-06-13 17:58:13 +0000741 target->saveCurrentDrawState(&record->fSavedState);
742 return true;
743}
744
745void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
746 const GrIRect& boundRect,
747 int tileX, int tileY,
748 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000749
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000750 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000751 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000752
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000753 GrPaint tempPaint;
754 tempPaint.reset();
755 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000756 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000757
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000758 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000759 int left = boundRect.fLeft + tileX * record->fTileSizeX;
760 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000761 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000762 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000763 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000764 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000765 target->postConcatViewMatrix(scaleM);
766
bsalomon@google.com91958362011-06-13 17:58:13 +0000767 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000768 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000769 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000770 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000771 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
772 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000773 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000774#if 0
775 // visualize tile boundaries by setting edges of offscreen to white
776 // and interior to tranparent. black.
777 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000778
bsalomon@google.com91958362011-06-13 17:58:13 +0000779 static const int gOffset = 2;
780 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
781 record->fScale * w - gOffset,
782 record->fScale * h - gOffset);
783 target->clear(&clear2, 0x0);
784#else
785 target->clear(&clear, 0x0);
786#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000787}
788
bsalomon@google.com91958362011-06-13 17:58:13 +0000789void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000790 const GrPaint& paint,
791 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000792 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000793 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000794 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000795 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000796 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000797 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000798 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
799 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000800 tileRect.fRight = (tileX == record->fTileCountX-1) ?
801 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000802 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000803 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
804 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000805 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000806
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000807 GrSamplerState::Filter filter;
808 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
809 filter = GrSamplerState::k4x4Downsample_Filter;
810 } else {
811 filter = GrSamplerState::kBilinear_Filter;
812 }
813
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000814 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000815 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000816 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000817
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000818 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000819 int scale;
820
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000821 enum {
822 kOffscreenStage = GrPaint::kTotalStages,
823 };
824
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000825 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000826 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000827 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000828 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000829
830 // Do 2x2 downsample from first to second
831 target->setTexture(kOffscreenStage, src);
832 target->setRenderTarget(dst);
833 target->setViewMatrix(GrMatrix::I());
834 sampleM.setScale(scale * GR_Scalar1 / src->width(),
835 scale * GR_Scalar1 / src->height());
836 sampler.setMatrix(sampleM);
837 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000838 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
839 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000840 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
841
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000842 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000843 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000844 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000845 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000846 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000847 } else {
848 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
849 record->fDownsample);
850 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 }
852
bsalomon@google.com91958362011-06-13 17:58:13 +0000853 // setup for draw back to main RT, we use the original
854 // draw state setup by the caller plus an additional coverage
855 // stage to handle the AA resolve. Also, we use an identity
856 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000857 int stageMask = paint.getActiveStageMask();
858
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000859 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000860 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000861
862 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000863 GrMatrix invVM;
864 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000865 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000866 }
867 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000868 // This is important when tiling, otherwise second tile's
869 // pass 1 view matrix will be incorrect.
870 GrDrawTarget::AutoViewMatrixRestore avmr(target);
871
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 target->setViewMatrix(GrMatrix::I());
873
874 target->setTexture(kOffscreenStage, src);
875 sampleM.setScale(scale * GR_Scalar1 / src->width(),
876 scale * GR_Scalar1 / src->height());
877 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000878 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000879 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000880 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000881
reed@google.com20efde72011-05-09 17:00:02 +0000882 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000883 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000884 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000885 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000886}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000887
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000888void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
889 GrPathRenderer* pr,
890 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000891 if (pr) {
892 // Counterpart of scale() in prepareForOffscreenAA()
893 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
894 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000895 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000896}
897
898////////////////////////////////////////////////////////////////////////////////
899
bsalomon@google.com27847de2011-02-22 20:59:41 +0000900/* create a triangle strip that strokes the specified triangle. There are 8
901 unique vertices, but we repreat the last 2 to close up. Alternatively we
902 could use an indices array, and then only send 8 verts, but not sure that
903 would be faster.
904 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000905static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000906 GrScalar width) {
907 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000909
910 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
911 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
912 verts[2].set(rect.fRight - rad, rect.fTop + rad);
913 verts[3].set(rect.fRight + rad, rect.fTop - rad);
914 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
915 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
916 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
917 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
918 verts[8] = verts[0];
919 verts[9] = verts[1];
920}
921
bsalomon@google.com205d4602011-04-25 12:43:45 +0000922static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000923 // FIXME: This was copied from SkGpuDevice, seems like
924 // we should have already smeared a in caller if that
925 // is what is desired.
926 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000927 unsigned a = GrColorUnpackA(paint.fColor);
928 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000929 } else {
930 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000931 }
932}
933
934static void setInsetFan(GrPoint* pts, size_t stride,
935 const GrRect& r, GrScalar dx, GrScalar dy) {
936 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
937}
938
939static const uint16_t gFillAARectIdx[] = {
940 0, 1, 5, 5, 4, 0,
941 1, 2, 6, 6, 5, 1,
942 2, 3, 7, 7, 6, 2,
943 3, 0, 4, 4, 7, 3,
944 4, 5, 6, 6, 7, 4,
945};
946
947int GrContext::aaFillRectIndexCount() const {
948 return GR_ARRAY_COUNT(gFillAARectIdx);
949}
950
951GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
952 if (NULL == fAAFillRectIndexBuffer) {
953 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
954 false);
955 GrAssert(NULL != fAAFillRectIndexBuffer);
956#if GR_DEBUG
957 bool updated =
958#endif
959 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
960 sizeof(gFillAARectIdx));
961 GR_DEBUGASSERT(updated);
962 }
963 return fAAFillRectIndexBuffer;
964}
965
966static const uint16_t gStrokeAARectIdx[] = {
967 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
968 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
969 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
970 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
971
972 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
973 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
974 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
975 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
976
977 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
978 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
979 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
980 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
981};
982
983int GrContext::aaStrokeRectIndexCount() const {
984 return GR_ARRAY_COUNT(gStrokeAARectIdx);
985}
986
987GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
988 if (NULL == fAAStrokeRectIndexBuffer) {
989 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
990 false);
991 GrAssert(NULL != fAAStrokeRectIndexBuffer);
992#if GR_DEBUG
993 bool updated =
994#endif
995 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
996 sizeof(gStrokeAARectIdx));
997 GR_DEBUGASSERT(updated);
998 }
999 return fAAStrokeRectIndexBuffer;
1000}
1001
1002void GrContext::fillAARect(GrDrawTarget* target,
1003 const GrPaint& paint,
1004 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001005 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1006 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001007
1008 size_t vsize = GrDrawTarget::VertexSize(layout);
1009
1010 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001011 if (!geo.succeeded()) {
1012 GrPrintf("Failed to get space for vertices!\n");
1013 return;
1014 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001015
1016 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1017
1018 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1019 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1020
1021 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1022 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1023
1024 verts += sizeof(GrPoint);
1025 for (int i = 0; i < 4; ++i) {
1026 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1027 }
1028
1029 GrColor innerColor = getColorForMesh(paint);
1030 verts += 4 * vsize;
1031 for (int i = 0; i < 4; ++i) {
1032 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1033 }
1034
1035 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
1036
1037 target->drawIndexed(kTriangles_PrimitiveType, 0,
1038 0, 8, this->aaFillRectIndexCount());
1039}
1040
1041void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1042 const GrRect& devRect, const GrVec& devStrokeSize) {
1043 const GrScalar& dx = devStrokeSize.fX;
1044 const GrScalar& dy = devStrokeSize.fY;
1045 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1046 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1047
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001048 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1049 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001050
1051 GrScalar spare;
1052 {
1053 GrScalar w = devRect.width() - dx;
1054 GrScalar h = devRect.height() - dy;
1055 spare = GrMin(w, h);
1056 }
1057
1058 if (spare <= 0) {
1059 GrRect r(devRect);
1060 r.inset(-rx, -ry);
1061 fillAARect(target, paint, r);
1062 return;
1063 }
1064
1065 size_t vsize = GrDrawTarget::VertexSize(layout);
1066
1067 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001068 if (!geo.succeeded()) {
1069 GrPrintf("Failed to get space for vertices!\n");
1070 return;
1071 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001072
1073 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1074
1075 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1076 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1077 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1078 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1079
1080 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1081 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1082 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1083 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1084
1085 verts += sizeof(GrPoint);
1086 for (int i = 0; i < 4; ++i) {
1087 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1088 }
1089
1090 GrColor innerColor = getColorForMesh(paint);
1091 verts += 4 * vsize;
1092 for (int i = 0; i < 8; ++i) {
1093 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1094 }
1095
1096 verts += 8 * vsize;
1097 for (int i = 0; i < 8; ++i) {
1098 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1099 }
1100
1101 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1102 target->drawIndexed(kTriangles_PrimitiveType,
1103 0, 0, 16, aaStrokeRectIndexCount());
1104}
1105
reed@google.com20efde72011-05-09 17:00:02 +00001106/**
1107 * Returns true if the rects edges are integer-aligned.
1108 */
1109static bool isIRect(const GrRect& r) {
1110 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1111 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1112}
1113
bsalomon@google.com205d4602011-04-25 12:43:45 +00001114static bool apply_aa_to_rect(GrDrawTarget* target,
1115 GrGpu* gpu,
1116 const GrPaint& paint,
1117 const GrRect& rect,
1118 GrScalar width,
1119 const GrMatrix* matrix,
1120 GrMatrix* combinedMatrix,
1121 GrRect* devRect) {
1122 // we use a simple alpha ramp to do aa on axis-aligned rects
1123 // do AA with alpha ramp if the caller requested AA, the rect
1124 // will be axis-aligned,the render target is not
1125 // multisampled, and the rect won't land on integer coords.
1126
1127 if (!paint.fAntiAlias) {
1128 return false;
1129 }
1130
1131 if (target->getRenderTarget()->isMultisampled()) {
1132 return false;
1133 }
1134
1135 if (0 == width && gpu->supportsAALines()) {
1136 return false;
1137 }
1138
1139 if (!target->getViewMatrix().preservesAxisAlignment()) {
1140 return false;
1141 }
1142
1143 if (NULL != matrix &&
1144 !matrix->preservesAxisAlignment()) {
1145 return false;
1146 }
1147
1148 *combinedMatrix = target->getViewMatrix();
1149 if (NULL != matrix) {
1150 combinedMatrix->preConcat(*matrix);
1151 GrAssert(combinedMatrix->preservesAxisAlignment());
1152 }
1153
1154 combinedMatrix->mapRect(devRect, rect);
1155 devRect->sort();
1156
1157 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001158 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001159 } else {
1160 return true;
1161 }
1162}
1163
bsalomon@google.com27847de2011-02-22 20:59:41 +00001164void GrContext::drawRect(const GrPaint& paint,
1165 const GrRect& rect,
1166 GrScalar width,
1167 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001168 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001169
1170 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001171 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001172
bsalomon@google.com205d4602011-04-25 12:43:45 +00001173 GrRect devRect = rect;
1174 GrMatrix combinedMatrix;
1175 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1176 &combinedMatrix, &devRect);
1177
1178 if (doAA) {
1179 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001180 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001181 GrMatrix inv;
1182 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001183 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001184 }
1185 }
1186 target->setViewMatrix(GrMatrix::I());
1187 if (width >= 0) {
1188 GrVec strokeSize;;
1189 if (width > 0) {
1190 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001191 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001192 strokeSize.setAbs(strokeSize);
1193 } else {
1194 strokeSize.set(GR_Scalar1, GR_Scalar1);
1195 }
1196 strokeAARect(target, paint, devRect, strokeSize);
1197 } else {
1198 fillAARect(target, paint, devRect);
1199 }
1200 return;
1201 }
1202
bsalomon@google.com27847de2011-02-22 20:59:41 +00001203 if (width >= 0) {
1204 // TODO: consider making static vertex buffers for these cases.
1205 // Hairline could be done by just adding closing vertex to
1206 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001207 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1208
bsalomon@google.com27847de2011-02-22 20:59:41 +00001209 static const int worstCaseVertCount = 10;
1210 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1211
1212 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001213 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001214 return;
1215 }
1216
1217 GrPrimitiveType primType;
1218 int vertCount;
1219 GrPoint* vertex = geo.positions();
1220
1221 if (width > 0) {
1222 vertCount = 10;
1223 primType = kTriangleStrip_PrimitiveType;
1224 setStrokeRectStrip(vertex, rect, width);
1225 } else {
1226 // hairline
1227 vertCount = 5;
1228 primType = kLineStrip_PrimitiveType;
1229 vertex[0].set(rect.fLeft, rect.fTop);
1230 vertex[1].set(rect.fRight, rect.fTop);
1231 vertex[2].set(rect.fRight, rect.fBottom);
1232 vertex[3].set(rect.fLeft, rect.fBottom);
1233 vertex[4].set(rect.fLeft, rect.fTop);
1234 }
1235
1236 GrDrawTarget::AutoViewMatrixRestore avmr;
1237 if (NULL != matrix) {
1238 avmr.set(target);
1239 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001240 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001241 }
1242
1243 target->drawNonIndexed(primType, 0, vertCount);
1244 } else {
1245 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001246 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001247 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1248 if (NULL == sqVB) {
1249 GrPrintf("Failed to create static rect vb.\n");
1250 return;
1251 }
1252 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001253 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1254 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001255 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001256 0, rect.height(), rect.fTop,
1257 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258
1259 if (NULL != matrix) {
1260 m.postConcat(*matrix);
1261 }
1262
1263 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001264 target->preConcatSamplerMatrices(stageMask, m);
1265
bsalomon@google.com27847de2011-02-22 20:59:41 +00001266 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1267 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001268 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269 #endif
1270 }
1271}
1272
1273void GrContext::drawRectToRect(const GrPaint& paint,
1274 const GrRect& dstRect,
1275 const GrRect& srcRect,
1276 const GrMatrix* dstMatrix,
1277 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001278 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001279
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001280 // srcRect refers to paint's first texture
1281 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001282 drawRect(paint, dstRect, -1, dstMatrix);
1283 return;
1284 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001285
bsalomon@google.com27847de2011-02-22 20:59:41 +00001286 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1287
1288#if GR_STATIC_RECT_VB
1289 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001290
1291 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1293
1294 GrMatrix m;
1295
1296 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1297 0, dstRect.height(), dstRect.fTop,
1298 0, 0, GrMatrix::I()[8]);
1299 if (NULL != dstMatrix) {
1300 m.postConcat(*dstMatrix);
1301 }
1302 target->preConcatViewMatrix(m);
1303
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001304 // srcRect refers to first stage
1305 int otherStageMask = paint.getActiveStageMask() &
1306 (~(1 << GrPaint::kFirstTextureStage));
1307 if (otherStageMask) {
1308 target->preConcatSamplerMatrices(otherStageMask, m);
1309 }
1310
bsalomon@google.com27847de2011-02-22 20:59:41 +00001311 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1312 0, srcRect.height(), srcRect.fTop,
1313 0, 0, GrMatrix::I()[8]);
1314 if (NULL != srcMatrix) {
1315 m.postConcat(*srcMatrix);
1316 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001317 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001318
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001319 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1320 if (NULL == sqVB) {
1321 GrPrintf("Failed to create static rect vb.\n");
1322 return;
1323 }
1324 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001325 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1326#else
1327
1328 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001329#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001330 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001331#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001332 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1333#endif
1334
1335 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1336 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1337 srcRects[0] = &srcRect;
1338 srcMatrices[0] = srcMatrix;
1339
1340 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1341#endif
1342}
1343
1344void GrContext::drawVertices(const GrPaint& paint,
1345 GrPrimitiveType primitiveType,
1346 int vertexCount,
1347 const GrPoint positions[],
1348 const GrPoint texCoords[],
1349 const GrColor colors[],
1350 const uint16_t indices[],
1351 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001352 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001353
1354 GrDrawTarget::AutoReleaseGeometry geo;
1355
1356 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1357
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001358 bool hasTexCoords[GrPaint::kTotalStages] = {
1359 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1360 0 // remaining stages use positions
1361 };
1362
1363 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001364
1365 if (NULL != colors) {
1366 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001367 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001368 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001369
1370 if (sizeof(GrPoint) != vertexSize) {
1371 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001372 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001373 return;
1374 }
1375 int texOffsets[GrDrawTarget::kMaxTexCoords];
1376 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001377 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1378 texOffsets,
1379 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001380 void* curVertex = geo.vertices();
1381
1382 for (int i = 0; i < vertexCount; ++i) {
1383 *((GrPoint*)curVertex) = positions[i];
1384
1385 if (texOffsets[0] > 0) {
1386 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1387 }
1388 if (colorOffset > 0) {
1389 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1390 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001391 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001392 }
1393 } else {
1394 target->setVertexSourceToArray(layout, positions, vertexCount);
1395 }
1396
bsalomon@google.com91958362011-06-13 17:58:13 +00001397 // we don't currently apply offscreen AA to this path. Need improved
1398 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001399
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001400 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001401 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001402 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001403 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001404 target->drawNonIndexed(primitiveType, 0, vertexCount);
1405 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001406}
1407
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001408///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001409
reed@google.com07f3ee12011-05-16 17:21:57 +00001410void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1411 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001412
bsalomon@google.com27847de2011-02-22 20:59:41 +00001413 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comee435122011-07-01 14:57:55 +00001414 GrPathRenderer* pr = this->getPathRenderer(path, fill);
1415 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1416 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001418 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001419 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001420
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001421 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001422
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001423 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001424 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1425 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001426 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001427 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001428 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001429 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001430 return;
1431 }
1432 }
reed@google.com70c136e2011-06-03 19:51:26 +00001433
reed@google.com07f3ee12011-05-16 17:21:57 +00001434 GrRect pathBounds = path.getBounds();
1435 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001436 if (NULL != translate) {
1437 pathBounds.offset(*translate);
1438 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001439 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001440 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001441 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001442 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001443 return;
1444 }
1445 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001446 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001447 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1448 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001449 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1450 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1451 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001452 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001453 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1454 }
1455 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001456 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001457 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001458 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1459 GrRect rect;
1460 if (clipIBounds.fTop < bound.fTop) {
1461 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1462 clipIBounds.fRight, bound.fTop);
1463 target->drawSimpleRect(rect, NULL, stageMask);
1464 }
1465 if (clipIBounds.fLeft < bound.fLeft) {
1466 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1467 bound.fLeft, bound.fBottom);
1468 target->drawSimpleRect(rect, NULL, stageMask);
1469 }
1470 if (clipIBounds.fRight > bound.fRight) {
1471 rect.setLTRB(bound.fRight, bound.fTop,
1472 clipIBounds.fRight, bound.fBottom);
1473 target->drawSimpleRect(rect, NULL, stageMask);
1474 }
1475 if (clipIBounds.fBottom > bound.fBottom) {
1476 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1477 clipIBounds.fRight, clipIBounds.fBottom);
1478 target->drawSimpleRect(rect, NULL, stageMask);
1479 }
1480 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001481 return;
1482 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001483 }
1484 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001485}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001486
bsalomon@google.com27847de2011-02-22 20:59:41 +00001487////////////////////////////////////////////////////////////////////////////////
1488
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001489void GrContext::flush(int flagsBitfield) {
1490 if (kDiscard_FlushBit & flagsBitfield) {
1491 fDrawBuffer->reset();
1492 } else {
1493 flushDrawBuffer();
1494 }
1495
1496 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001497 fGpu->forceRenderTargetFlush();
1498 }
1499}
1500
1501void GrContext::flushText() {
1502 if (kText_DrawCategory == fLastDrawCategory) {
1503 flushDrawBuffer();
1504 }
1505}
1506
1507void GrContext::flushDrawBuffer() {
1508#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001509 if (fDrawBuffer) {
1510 fDrawBuffer->playback(fGpu);
1511 fDrawBuffer->reset();
1512 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001513#endif
1514}
1515
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001516bool GrContext::readTexturePixels(GrTexture* texture,
1517 int left, int top, int width, int height,
1518 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001519 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001520
1521 // TODO: code read pixels for textures that aren't rendertargets
1522
1523 this->flush();
1524 GrRenderTarget* target = texture->asRenderTarget();
1525 if (NULL != target) {
1526 return fGpu->readPixels(target,
1527 left, top, width, height,
1528 config, buffer);
1529 } else {
1530 return false;
1531 }
1532}
1533
1534bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1535 int left, int top, int width, int height,
1536 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001537 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001538 uint32_t flushFlags = 0;
1539 if (NULL == target) {
1540 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1541 }
1542
1543 this->flush(flushFlags);
1544 return fGpu->readPixels(target,
1545 left, top, width, height,
1546 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001547}
1548
1549void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001550 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001551 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001552 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001553
1554 // TODO: when underlying api has a direct way to do this we should use it
1555 // (e.g. glDrawPixels on desktop GL).
1556
bsalomon@google.com5c638652011-07-18 19:31:59 +00001557 this->flush(true);
1558
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001559 const GrTextureDesc desc = {
1560 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001561 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001562 GrAutoScratchTexture ast(this, desc);
1563 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001564 if (NULL == texture) {
1565 return;
1566 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001567 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001568
bsalomon@google.com27847de2011-02-22 20:59:41 +00001569 GrDrawTarget::AutoStateRestore asr(fGpu);
1570
1571 GrMatrix matrix;
1572 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1573 fGpu->setViewMatrix(matrix);
1574
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001575 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001576 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1577 fGpu->setAlpha(0xFF);
1578 fGpu->setBlendFunc(kOne_BlendCoeff,
1579 kZero_BlendCoeff);
1580 fGpu->setTexture(0, texture);
1581
1582 GrSamplerState sampler;
1583 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001584 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001585 sampler.setMatrix(matrix);
1586 fGpu->setSamplerState(0, sampler);
1587
1588 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1589 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001590 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001591 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1592 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001593 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001594 return;
1595 }
1596 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1597 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1598}
1599////////////////////////////////////////////////////////////////////////////////
1600
1601void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001602
1603 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1604 int s = i + GrPaint::kFirstTextureStage;
1605 target->setTexture(s, paint.getTexture(i));
1606 target->setSamplerState(s, *paint.getTextureSampler(i));
1607 }
1608
1609 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1610
1611 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1612 int s = i + GrPaint::kFirstMaskStage;
1613 target->setTexture(s, paint.getMask(i));
1614 target->setSamplerState(s, *paint.getMaskSampler(i));
1615 }
1616
bsalomon@google.com27847de2011-02-22 20:59:41 +00001617 target->setColor(paint.fColor);
1618
1619 if (paint.fDither) {
1620 target->enableState(GrDrawTarget::kDither_StateBit);
1621 } else {
1622 target->disableState(GrDrawTarget::kDither_StateBit);
1623 }
1624 if (paint.fAntiAlias) {
1625 target->enableState(GrDrawTarget::kAntialias_StateBit);
1626 } else {
1627 target->disableState(GrDrawTarget::kAntialias_StateBit);
1628 }
1629 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001630 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001631}
1632
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001633GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001634 DrawCategory category) {
1635 if (category != fLastDrawCategory) {
1636 flushDrawBuffer();
1637 fLastDrawCategory = category;
1638 }
1639 SetPaint(paint, fGpu);
1640 GrDrawTarget* target = fGpu;
1641 switch (category) {
1642 case kText_DrawCategory:
1643#if DEFER_TEXT_RENDERING
1644 target = fDrawBuffer;
1645 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1646#else
1647 target = fGpu;
1648#endif
1649 break;
1650 case kUnbuffered_DrawCategory:
1651 target = fGpu;
1652 break;
1653 case kBuffered_DrawCategory:
1654 target = fDrawBuffer;
1655 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1656 break;
1657 }
1658 return target;
1659}
1660
1661////////////////////////////////////////////////////////////////////////////////
1662
bsalomon@google.com27847de2011-02-22 20:59:41 +00001663void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001664 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001665 fGpu->setRenderTarget(target);
1666}
1667
1668GrRenderTarget* GrContext::getRenderTarget() {
1669 return fGpu->getRenderTarget();
1670}
1671
1672const GrRenderTarget* GrContext::getRenderTarget() const {
1673 return fGpu->getRenderTarget();
1674}
1675
1676const GrMatrix& GrContext::getMatrix() const {
1677 return fGpu->getViewMatrix();
1678}
1679
1680void GrContext::setMatrix(const GrMatrix& m) {
1681 fGpu->setViewMatrix(m);
1682}
1683
1684void GrContext::concatMatrix(const GrMatrix& m) const {
1685 fGpu->preConcatViewMatrix(m);
1686}
1687
1688static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1689 intptr_t mask = 1 << shift;
1690 if (pred) {
1691 bits |= mask;
1692 } else {
1693 bits &= ~mask;
1694 }
1695 return bits;
1696}
1697
1698void GrContext::resetStats() {
1699 fGpu->resetStats();
1700}
1701
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001702const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001703 return fGpu->getStats();
1704}
1705
1706void GrContext::printStats() const {
1707 fGpu->printStats();
1708}
1709
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001710GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001711 fGpu = gpu;
1712 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001713 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001714
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001715 fDefaultPathRenderer =
1716 new GrDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1717 gpu->supportsStencilWrapOps());
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001718 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1719 fGpu->setClipPathRenderer(fCustomPathRenderer);
1720
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001721 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1722 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001723 fFontCache = new GrFontCache(fGpu);
1724
1725 fLastDrawCategory = kUnbuffered_DrawCategory;
1726
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001727 fDrawBuffer = NULL;
1728 fDrawBufferVBAllocPool = NULL;
1729 fDrawBufferIBAllocPool = NULL;
1730
bsalomon@google.com205d4602011-04-25 12:43:45 +00001731 fAAFillRectIndexBuffer = NULL;
1732 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001733
1734 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1735 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1736 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1737 }
1738 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001739
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001740 this->setupDrawBuffer();
1741}
1742
1743void GrContext::setupDrawBuffer() {
1744
1745 GrAssert(NULL == fDrawBuffer);
1746 GrAssert(NULL == fDrawBufferVBAllocPool);
1747 GrAssert(NULL == fDrawBufferIBAllocPool);
1748
bsalomon@google.com27847de2011-02-22 20:59:41 +00001749#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001750 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001751 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001752 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1753 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001754 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001755 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001756 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001757 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1758
1759 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1760 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001761#endif
1762
1763#if BATCH_RECT_TO_RECT
1764 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1765#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001766}
1767
bsalomon@google.com27847de2011-02-22 20:59:41 +00001768GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1769 GrDrawTarget* target;
1770#if DEFER_TEXT_RENDERING
1771 target = prepareToDraw(paint, kText_DrawCategory);
1772#else
1773 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1774#endif
1775 SetPaint(paint, target);
1776 return target;
1777}
1778
1779const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1780 return fGpu->getQuadIndexBuffer();
1781}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001782
bsalomon@google.comee435122011-07-01 14:57:55 +00001783GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001784 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001785 if (NULL != fCustomPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +00001786 fCustomPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001787 return fCustomPathRenderer;
1788 } else {
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001789 GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
1790 return fDefaultPathRenderer;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001791 }
1792}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001793
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001794void GrContext::convolveInX(GrTexture* texture,
1795 const SkRect& rect,
1796 const float* kernel,
1797 int kernelWidth) {
1798 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1799 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1800}
1801
1802void GrContext::convolveInY(GrTexture* texture,
1803 const SkRect& rect,
1804 const float* kernel,
1805 int kernelWidth) {
1806 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1807 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1808}
1809
1810void GrContext::convolve(GrTexture* texture,
1811 const SkRect& rect,
1812 float imageIncrement[2],
1813 const float* kernel,
1814 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001815 GrDrawTarget::AutoStateRestore asr(fGpu);
1816 GrMatrix sampleM;
1817 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1818 GrSamplerState::kClamp_WrapMode,
1819 GrSamplerState::kConvolution_Filter);
1820 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001821 sampleM.setScale(GR_Scalar1 / texture->width(),
1822 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001823 sampler.setMatrix(sampleM);
1824 fGpu->setSamplerState(0, sampler);
1825 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001826 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001827 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001828 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1829}