blob: d1de73496f395e3d8e33f3dbcf854a46e9fc8e4a [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.comdfe75bc2011-03-25 12:31:16 +000064 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000065 GrSafeUnref(fAAFillRectIndexBuffer);
66 GrSafeUnref(fAAStrokeRectIndexBuffer);
67 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000068}
69
bsalomon@google.com8fe72472011-03-30 21:26:44 +000070void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000071 contextDestroyed();
72 this->setupDrawBuffer();
73}
74
75void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000076 // abandon first to so destructors
77 // don't try to free the resources in the API.
78 fGpu->abandonResources();
79
bsalomon@google.com8fe72472011-03-30 21:26:44 +000080 delete fDrawBuffer;
81 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000082
bsalomon@google.com8fe72472011-03-30 21:26:44 +000083 delete fDrawBufferVBAllocPool;
84 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000085
bsalomon@google.com8fe72472011-03-30 21:26:44 +000086 delete fDrawBufferIBAllocPool;
87 fDrawBufferIBAllocPool = NULL;
88
bsalomon@google.com205d4602011-04-25 12:43:45 +000089 GrSafeSetNull(fAAFillRectIndexBuffer);
90 GrSafeSetNull(fAAStrokeRectIndexBuffer);
91
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 fTextureCache->removeAll();
93 fFontCache->freeAll();
94 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095}
96
97void GrContext::resetContext() {
98 fGpu->markContextDirty();
99}
100
101void GrContext::freeGpuResources() {
102 this->flush();
103 fTextureCache->removeAll();
104 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000105}
106
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000107////////////////////////////////////////////////////////////////////////////////
108
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000109int GrContext::PaintStageVertexLayoutBits(
110 const GrPaint& paint,
111 const bool hasTexCoords[GrPaint::kTotalStages]) {
112 int stageMask = paint.getActiveStageMask();
113 int layout = 0;
114 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
115 if ((1 << i) & stageMask) {
116 if (NULL != hasTexCoords && hasTexCoords[i]) {
117 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
118 } else {
119 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
120 }
121 }
122 }
123 return layout;
124}
125
126
127////////////////////////////////////////////////////////////////////////////////
128
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000129enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000130 // flags for textures
131 kNPOTBit = 0x1,
132 kFilterBit = 0x2,
133 kScratchBit = 0x4,
134
135 // resource type
136 kTextureBit = 0x8,
137 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000138};
139
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000140GrTexture* GrContext::TextureCacheEntry::texture() const {
141 if (NULL == fEntry) {
142 return NULL;
143 } else {
144 return (GrTexture*) fEntry->resource();
145 }
146}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000147
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000148namespace {
149// returns true if this is a "special" texture because of gpu NPOT limitations
150bool gen_texture_key_values(const GrGpu* gpu,
151 const GrSamplerState& sampler,
152 GrContext::TextureKey clientKey,
153 int width,
154 int height,
155 bool scratch,
156 uint32_t v[4]) {
157 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
158 // we assume we only need 16 bits of width and height
159 // assert that texture creation will fail anyway if this assumption
160 // would cause key collisions.
161 GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
162 v[0] = clientKey & 0xffffffffUL;
163 v[1] = (clientKey >> 32) & 0xffffffffUL;
164 v[2] = width | (height << 16);
165
166 v[3] = 0;
167 if (!gpu->npotTextureTileSupport()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000168 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
169
170 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
171 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
172
173 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000174 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000175 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000176 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000177 }
178 }
179 }
180
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000181 if (scratch) {
182 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000183 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000184
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000185 v[3] |= kTextureBit;
186
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000187 return v[3] & kNPOTBit;
188}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000189
190// we should never have more than one stencil buffer with same combo of
191// (width,height,samplecount)
192void gen_stencil_key_values(int width, int height,
193 int sampleCnt, uint32_t v[4]) {
194 v[0] = width;
195 v[1] = height;
196 v[2] = sampleCnt;
197 v[3] = kStencilBufferBit;
198}
199
200void gen_stencil_key_values(const GrStencilBuffer* sb,
201 uint32_t v[4]) {
202 gen_stencil_key_values(sb->width(), sb->height(),
203 sb->numSamples(), v);
204}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000205}
206
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000207GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
208 int width,
209 int height,
210 const GrSamplerState& sampler) {
211 uint32_t v[4];
212 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
213 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000214 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
215 GrResourceCache::kNested_LockType));
216}
217
218GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
219 uint32_t v[4];
220 gen_stencil_key_values(sb, v);
221 GrResourceKey resourceKey(v);
222 return fTextureCache->createAndLock(resourceKey, sb);
223}
224
225GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
226 int sampleCnt) {
227 uint32_t v[4];
228 gen_stencil_key_values(width, height, sampleCnt, v);
229 GrResourceKey resourceKey(v);
230 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
231 GrResourceCache::kSingle_LockType);
232 if (NULL != entry) {
233 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
234 return sb;
235 } else {
236 return NULL;
237 }
238}
239
240void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
241 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000242}
243
244static void stretchImage(void* dst,
245 int dstW,
246 int dstH,
247 void* src,
248 int srcW,
249 int srcH,
250 int bpp) {
251 GrFixed dx = (srcW << 16) / dstW;
252 GrFixed dy = (srcH << 16) / dstH;
253
254 GrFixed y = dy >> 1;
255
256 int dstXLimit = dstW*bpp;
257 for (int j = 0; j < dstH; ++j) {
258 GrFixed x = dx >> 1;
259 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
260 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
261 for (int i = 0; i < dstXLimit; i += bpp) {
262 memcpy((uint8_t*) dstRow + i,
263 (uint8_t*) srcRow + (x>>16)*bpp,
264 bpp);
265 x += dx;
266 }
267 y += dy;
268 }
269}
270
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000271GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000272 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000273 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000274 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000275 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000276
277#if GR_DUMP_TEXTURE_UPLOAD
278 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
279#endif
280
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000281 TextureCacheEntry entry;
282 uint32_t v[4];
283 bool special = gen_texture_key_values(fGpu, sampler, key,
284 desc.fWidth, desc.fHeight, false, v);
285 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000286
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000287 if (special) {
288 TextureCacheEntry clampEntry =
289 findAndLockTexture(key, desc.fWidth, desc.fHeight,
290 GrSamplerState::ClampNoFilter());
291
292 if (NULL == clampEntry.texture()) {
293 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000294 GrSamplerState::ClampNoFilter(),
295 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000296 GrAssert(NULL != clampEntry.texture());
297 if (NULL == clampEntry.texture()) {
298 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000299 }
300 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000301 GrTextureDesc rtDesc = desc;
302 rtDesc.fFlags = rtDesc.fFlags |
303 kRenderTarget_GrTextureFlagBit |
304 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000305 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
306 fGpu->minRenderTargetWidth()));
307 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
308 fGpu->minRenderTargetHeight()));
309
310 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
311
312 if (NULL != texture) {
313 GrDrawTarget::AutoStateRestore asr(fGpu);
314 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000315 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000316 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000317 fGpu->setViewMatrix(GrMatrix::I());
318 fGpu->setAlpha(0xff);
319 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
320 fGpu->disableState(GrDrawTarget::kDither_StateBit |
321 GrDrawTarget::kClip_StateBit |
322 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000323 GrSamplerState::Filter filter;
324 // if filtering is not desired then we want to ensure all
325 // texels in the resampled image are copies of texels from
326 // the original.
327 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
328 filter = GrSamplerState::kNearest_Filter;
329 } else {
330 filter = GrSamplerState::kBilinear_Filter;
331 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000332 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
333 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000334 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000335 fGpu->setSamplerState(0, stretchSampler);
336
337 static const GrVertexLayout layout =
338 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
339 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
340
341 if (arg.succeeded()) {
342 GrPoint* verts = (GrPoint*) arg.vertices();
343 verts[0].setIRectFan(0, 0,
344 texture->width(),
345 texture->height(),
346 2*sizeof(GrPoint));
347 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
348 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
349 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000350 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000351 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000352 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000353 } else {
354 // TODO: Our CPU stretch doesn't filter. But we create separate
355 // stretched textures when the sampler state is either filtered or
356 // not. Either implement filtered stretch blit on CPU or just create
357 // one when FBO case fails.
358
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000359 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000360 // no longer need to clamp at min RT size.
361 rtDesc.fWidth = GrNextPow2(desc.fWidth);
362 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000363 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000364 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000365 rtDesc.fWidth *
366 rtDesc.fHeight);
367 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
368 srcData, desc.fWidth, desc.fHeight, bpp);
369
370 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
371
372 GrTexture* texture = fGpu->createTexture(rtDesc,
373 stretchedPixels.get(),
374 stretchedRowBytes);
375 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000376 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000377 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000378 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000379
380 } else {
381 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
382 if (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 }
385 }
386 return entry;
387}
388
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000389namespace {
390inline void gen_scratch_tex_key_values(const GrGpu* gpu,
391 const GrTextureDesc& desc,
392 uint32_t v[4]) {
393 // Instead of a client-provided key of the texture contents
394 // we create a key of from the descriptor.
395 GrContext::TextureKey descKey = desc.fAALevel |
396 (desc.fFlags << 8) |
397 ((uint64_t) desc.fFormat << 32);
398 // this code path isn't friendly to tiling with NPOT restricitons
399 // We just pass ClampNoFilter()
400 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
401 desc.fWidth, desc.fHeight, true, v);
402}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000403}
404
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000405GrContext::TextureCacheEntry GrContext::lockScratchTexture(
406 const GrTextureDesc& inDesc,
407 ScratchTexMatch match) {
408
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000409 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000410 if (kExact_ScratchTexMatch != match) {
411 // bin by pow2 with a reasonable min
412 static const int MIN_SIZE = 256;
413 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
414 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
415 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000416
417 uint32_t p0 = desc.fFormat;
418 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
419
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000420 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000421 int origWidth = desc.fWidth;
422 int origHeight = desc.fHeight;
423 bool doubledW = false;
424 bool doubledH = false;
425
426 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427 uint32_t v[4];
428 gen_scratch_tex_key_values(fGpu, desc, v);
429 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000430 entry = fTextureCache->findAndLock(key,
431 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000432 // if we miss, relax the fit of the flags...
433 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000435 break;
436 }
437 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
438 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
439 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
440 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
441 } else if (!doubledW) {
442 desc.fFlags = inDesc.fFlags;
443 desc.fWidth *= 2;
444 doubledW = true;
445 } else if (!doubledH) {
446 desc.fFlags = inDesc.fFlags;
447 desc.fWidth = origWidth;
448 desc.fHeight *= 2;
449 doubledH = true;
450 } else {
451 break;
452 }
453
454 } while (true);
455
456 if (NULL == entry) {
457 desc.fFlags = inDesc.fFlags;
458 desc.fWidth = origWidth;
459 desc.fHeight = origHeight;
460 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
461 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000462 uint32_t v[4];
463 gen_scratch_tex_key_values(fGpu, desc, v);
464 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000465 entry = fTextureCache->createAndLock(key, texture);
466 }
467 }
468
469 // If the caller gives us the same desc/sampler twice we don't want
470 // to return the same texture the second time (unless it was previously
471 // released). So we detach the entry from the cache and reattach at release.
472 if (NULL != entry) {
473 fTextureCache->detach(entry);
474 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000475 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000476}
477
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000478void GrContext::unlockTexture(TextureCacheEntry entry) {
479 // If this is a scratch texture we detached it from the cache
480 // while it was locked (to avoid two callers simultaneously getting
481 // the same texture).
482 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
483 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000484 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000486 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000487}
488
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000489GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000490 void* srcData,
491 size_t rowBytes) {
492 return fGpu->createTexture(desc, srcData, rowBytes);
493}
494
495void GrContext::getTextureCacheLimits(int* maxTextures,
496 size_t* maxTextureBytes) const {
497 fTextureCache->getLimits(maxTextures, maxTextureBytes);
498}
499
500void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
501 fTextureCache->setLimits(maxTextures, maxTextureBytes);
502}
503
bsalomon@google.com91958362011-06-13 17:58:13 +0000504int GrContext::getMaxTextureSize() const {
505 return fGpu->maxTextureSize();
506}
507
508int GrContext::getMaxRenderTargetSize() const {
509 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000510}
511
512///////////////////////////////////////////////////////////////////////////////
513
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000514GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
515 // validate flags here so that GrGpu subclasses don't have to check
516 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
517 0 != desc.fRenderTargetFlags) {
518 return NULL;
519 }
bsalomon@google.com47370822011-08-02 15:29:38 +0000520#if !GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000521 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
522 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
523 return NULL;
524 }
525 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
526 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
527 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
528 return NULL;
529 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000530#else
531 if (desc.fSampleCnt &&
532 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
533 return NULL;
534 }
535 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
536 desc.fSampleCnt &&
537 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
538 return NULL;
539 }
540#endif
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000541 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000542}
543
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000544GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000545 return fGpu->createRenderTargetFrom3DApiState();
546}
547
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000548///////////////////////////////////////////////////////////////////////////////
549
bsalomon@google.com27847de2011-02-22 20:59:41 +0000550bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
551 int width, int height) {
552 if (!fGpu->supports8BitPalette()) {
553 return false;
554 }
555
556
557 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
558
559 if (!isPow2) {
560 if (!fGpu->npotTextureSupport()) {
561 return false;
562 }
563
564 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
565 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
566 if (tiled && !fGpu->npotTextureTileSupport()) {
567 return false;
568 }
569 }
570 return true;
571}
572
573////////////////////////////////////////////////////////////////////////////////
574
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000575const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
576
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577void GrContext::setClip(const GrClip& clip) {
578 fGpu->setClip(clip);
579 fGpu->enableState(GrDrawTarget::kClip_StateBit);
580}
581
582void GrContext::setClip(const GrIRect& rect) {
583 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000584 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000585 fGpu->setClip(clip);
586}
587
588////////////////////////////////////////////////////////////////////////////////
589
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000590void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000591 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000592 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000593}
594
595void GrContext::drawPaint(const GrPaint& paint) {
596 // set rect to be big enough to fill the space, but not super-huge, so we
597 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000598 GrRect r;
599 r.setLTRB(0, 0,
600 GrIntToScalar(getRenderTarget()->width()),
601 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000602 GrMatrix inverse;
603 if (fGpu->getViewInverse(&inverse)) {
604 inverse.mapRect(&r);
605 } else {
606 GrPrintf("---- fGpu->getViewInverse failed\n");
607 }
608 this->drawRect(paint, r);
609}
610
bsalomon@google.com205d4602011-04-25 12:43:45 +0000611////////////////////////////////////////////////////////////////////////////////
612
bsalomon@google.com91958362011-06-13 17:58:13 +0000613struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000614 enum Downsample {
615 k4x4TwoPass_Downsample,
616 k4x4SinglePass_Downsample,
617 kFSAA_Downsample
618 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000619 int fTileSizeX;
620 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000621 int fTileCountX;
622 int fTileCountY;
623 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000624 GrAutoScratchTexture fOffscreen0;
625 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000626 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000627 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000628};
629
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000630bool GrContext::doOffscreenAA(GrDrawTarget* target,
631 const GrPaint& paint,
632 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000633#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000634 return false;
635#else
636 if (!paint.fAntiAlias) {
637 return false;
638 }
639 if (isLines && fGpu->supportsAALines()) {
640 return false;
641 }
642 if (target->getRenderTarget()->isMultisampled()) {
643 return false;
644 }
645 // we have to be sure that the blend equation is expressible
646 // as simple src / dst coeffecients when the source
647 // is already modulated by the coverage fraction.
648 // We could use dual-source blending to get the correct per-pixel
649 // dst coeffecient for the remaining cases.
650 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
651 kOne_BlendCoeff != paint.fDstBlendCoeff &&
652 kISA_BlendCoeff != paint.fDstBlendCoeff) {
653 return false;
654 }
655 return true;
656#endif
657}
658
bsalomon@google.com91958362011-06-13 17:58:13 +0000659bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000660 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000661 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000662 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000663 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000664
665 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000666
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000667 GrAssert(NULL == record->fOffscreen0.texture());
668 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000669 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000670
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000671 int boundW = boundRect.width();
672 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000673
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000674 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000675
676 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
677 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
678
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000679 if (requireStencil) {
680 desc.fFlags = kRenderTarget_GrTextureFlagBit;
681 } else {
682 desc.fFlags = kRenderTarget_GrTextureFlagBit |
683 kNoStencil_GrTextureFlagBit;
684 }
685
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000686 desc.fFormat = kRGBA_8888_GrPixelConfig;
687
bsalomon@google.com91958362011-06-13 17:58:13 +0000688 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000689 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000690 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000691 desc.fAALevel = kMed_GrAALevel;
692 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000693 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
694 OffscreenRecord::k4x4SinglePass_Downsample :
695 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000696 record->fScale = OFFSCREEN_SSAA_SCALE;
697 // both downsample paths assume this
698 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000699 desc.fAALevel = kNone_GrAALevel;
700 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000701 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
702 // of simple circles?
703 if (pr) {
704 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
705 }
706
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000707 desc.fWidth *= record->fScale;
708 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000709 record->fOffscreen0.set(this, desc);
710 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000711 return false;
712 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000713 // the approximate lookup might have given us some slop space, might as well
714 // use it when computing the tiles size.
715 // these are scale values, will adjust after considering
716 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000717 record->fTileSizeX = record->fOffscreen0.texture()->width();
718 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000719
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000720 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000721 desc.fWidth /= 2;
722 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000723 record->fOffscreen1.set(this, desc);
724 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000725 return false;
726 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000727 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000728 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000729 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000730 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000731 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000732 record->fTileSizeX /= record->fScale;
733 record->fTileSizeY /= record->fScale;
734
735 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
736 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
737
tomhudson@google.com237a4612011-07-19 15:44:00 +0000738 record->fClip = target->getClip();
739
bsalomon@google.com91958362011-06-13 17:58:13 +0000740 target->saveCurrentDrawState(&record->fSavedState);
741 return true;
742}
743
744void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
745 const GrIRect& boundRect,
746 int tileX, int tileY,
747 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000748
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000749 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000750 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000751
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000752 GrPaint tempPaint;
753 tempPaint.reset();
754 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000755 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000756
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000757 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000758 int left = boundRect.fLeft + tileX * record->fTileSizeX;
759 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000760 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000761 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000762 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000763 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000764 target->postConcatViewMatrix(scaleM);
765
bsalomon@google.com91958362011-06-13 17:58:13 +0000766 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000767 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000768 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000769 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000770 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
771 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000772 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000773#if 0
774 // visualize tile boundaries by setting edges of offscreen to white
775 // and interior to tranparent. black.
776 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000777
bsalomon@google.com91958362011-06-13 17:58:13 +0000778 static const int gOffset = 2;
779 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
780 record->fScale * w - gOffset,
781 record->fScale * h - gOffset);
782 target->clear(&clear2, 0x0);
783#else
784 target->clear(&clear, 0x0);
785#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000786}
787
bsalomon@google.com91958362011-06-13 17:58:13 +0000788void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000789 const GrPaint& paint,
790 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000791 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000792 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000793 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000794 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000795 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000796 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000797 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
798 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000799 tileRect.fRight = (tileX == record->fTileCountX-1) ?
800 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000801 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000802 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
803 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000804 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000805
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000806 GrSamplerState::Filter filter;
807 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
808 filter = GrSamplerState::k4x4Downsample_Filter;
809 } else {
810 filter = GrSamplerState::kBilinear_Filter;
811 }
812
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000813 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000814 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000815 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000816
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000817 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000818 int scale;
819
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000820 enum {
821 kOffscreenStage = GrPaint::kTotalStages,
822 };
823
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000824 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000825 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000826 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000827 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000828
829 // Do 2x2 downsample from first to second
830 target->setTexture(kOffscreenStage, src);
831 target->setRenderTarget(dst);
832 target->setViewMatrix(GrMatrix::I());
833 sampleM.setScale(scale * GR_Scalar1 / src->width(),
834 scale * GR_Scalar1 / src->height());
835 sampler.setMatrix(sampleM);
836 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000837 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
838 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000839 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
840
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000841 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000842 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000843 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000844 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000845 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000846 } else {
847 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
848 record->fDownsample);
849 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000850 }
851
bsalomon@google.com91958362011-06-13 17:58:13 +0000852 // setup for draw back to main RT, we use the original
853 // draw state setup by the caller plus an additional coverage
854 // stage to handle the AA resolve. Also, we use an identity
855 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000856 int stageMask = paint.getActiveStageMask();
857
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000858 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000859 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000860
861 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000862 GrMatrix invVM;
863 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000864 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000865 }
866 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000867 // This is important when tiling, otherwise second tile's
868 // pass 1 view matrix will be incorrect.
869 GrDrawTarget::AutoViewMatrixRestore avmr(target);
870
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871 target->setViewMatrix(GrMatrix::I());
872
873 target->setTexture(kOffscreenStage, src);
874 sampleM.setScale(scale * GR_Scalar1 / src->width(),
875 scale * GR_Scalar1 / src->height());
876 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000877 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000878 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000879 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000880
reed@google.com20efde72011-05-09 17:00:02 +0000881 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000882 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000883 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000884 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000885}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000886
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000887void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
888 GrPathRenderer* pr,
889 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000890 if (pr) {
891 // Counterpart of scale() in prepareForOffscreenAA()
892 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
893 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000894 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000895}
896
897////////////////////////////////////////////////////////////////////////////////
898
bsalomon@google.com27847de2011-02-22 20:59:41 +0000899/* create a triangle strip that strokes the specified triangle. There are 8
900 unique vertices, but we repreat the last 2 to close up. Alternatively we
901 could use an indices array, and then only send 8 verts, but not sure that
902 would be faster.
903 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000904static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000905 GrScalar width) {
906 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000907 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000908
909 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
910 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
911 verts[2].set(rect.fRight - rad, rect.fTop + rad);
912 verts[3].set(rect.fRight + rad, rect.fTop - rad);
913 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
914 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
915 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
916 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
917 verts[8] = verts[0];
918 verts[9] = verts[1];
919}
920
bsalomon@google.com205d4602011-04-25 12:43:45 +0000921static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000922 // FIXME: This was copied from SkGpuDevice, seems like
923 // we should have already smeared a in caller if that
924 // is what is desired.
925 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000926 unsigned a = GrColorUnpackA(paint.fColor);
927 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000928 } else {
929 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000930 }
931}
932
933static void setInsetFan(GrPoint* pts, size_t stride,
934 const GrRect& r, GrScalar dx, GrScalar dy) {
935 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
936}
937
938static const uint16_t gFillAARectIdx[] = {
939 0, 1, 5, 5, 4, 0,
940 1, 2, 6, 6, 5, 1,
941 2, 3, 7, 7, 6, 2,
942 3, 0, 4, 4, 7, 3,
943 4, 5, 6, 6, 7, 4,
944};
945
946int GrContext::aaFillRectIndexCount() const {
947 return GR_ARRAY_COUNT(gFillAARectIdx);
948}
949
950GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
951 if (NULL == fAAFillRectIndexBuffer) {
952 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
953 false);
954 GrAssert(NULL != fAAFillRectIndexBuffer);
955#if GR_DEBUG
956 bool updated =
957#endif
958 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
959 sizeof(gFillAARectIdx));
960 GR_DEBUGASSERT(updated);
961 }
962 return fAAFillRectIndexBuffer;
963}
964
965static const uint16_t gStrokeAARectIdx[] = {
966 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
967 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
968 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
969 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
970
971 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
972 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
973 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
974 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
975
976 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
977 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
978 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
979 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
980};
981
982int GrContext::aaStrokeRectIndexCount() const {
983 return GR_ARRAY_COUNT(gStrokeAARectIdx);
984}
985
986GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
987 if (NULL == fAAStrokeRectIndexBuffer) {
988 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
989 false);
990 GrAssert(NULL != fAAStrokeRectIndexBuffer);
991#if GR_DEBUG
992 bool updated =
993#endif
994 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
995 sizeof(gStrokeAARectIdx));
996 GR_DEBUGASSERT(updated);
997 }
998 return fAAStrokeRectIndexBuffer;
999}
1000
1001void GrContext::fillAARect(GrDrawTarget* target,
1002 const GrPaint& paint,
1003 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001004 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1005 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001006
1007 size_t vsize = GrDrawTarget::VertexSize(layout);
1008
1009 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001010 if (!geo.succeeded()) {
1011 GrPrintf("Failed to get space for vertices!\n");
1012 return;
1013 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001014
1015 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1016
1017 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1018 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1019
1020 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1021 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1022
1023 verts += sizeof(GrPoint);
1024 for (int i = 0; i < 4; ++i) {
1025 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1026 }
1027
1028 GrColor innerColor = getColorForMesh(paint);
1029 verts += 4 * vsize;
1030 for (int i = 0; i < 4; ++i) {
1031 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1032 }
1033
1034 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
1035
1036 target->drawIndexed(kTriangles_PrimitiveType, 0,
1037 0, 8, this->aaFillRectIndexCount());
1038}
1039
1040void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1041 const GrRect& devRect, const GrVec& devStrokeSize) {
1042 const GrScalar& dx = devStrokeSize.fX;
1043 const GrScalar& dy = devStrokeSize.fY;
1044 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1045 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1046
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001047 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1048 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001049
1050 GrScalar spare;
1051 {
1052 GrScalar w = devRect.width() - dx;
1053 GrScalar h = devRect.height() - dy;
1054 spare = GrMin(w, h);
1055 }
1056
1057 if (spare <= 0) {
1058 GrRect r(devRect);
1059 r.inset(-rx, -ry);
1060 fillAARect(target, paint, r);
1061 return;
1062 }
1063
1064 size_t vsize = GrDrawTarget::VertexSize(layout);
1065
1066 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001067 if (!geo.succeeded()) {
1068 GrPrintf("Failed to get space for vertices!\n");
1069 return;
1070 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001071
1072 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1073
1074 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1075 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1076 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1077 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1078
1079 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1080 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1081 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1082 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1083
1084 verts += sizeof(GrPoint);
1085 for (int i = 0; i < 4; ++i) {
1086 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1087 }
1088
1089 GrColor innerColor = getColorForMesh(paint);
1090 verts += 4 * vsize;
1091 for (int i = 0; i < 8; ++i) {
1092 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1093 }
1094
1095 verts += 8 * vsize;
1096 for (int i = 0; i < 8; ++i) {
1097 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1098 }
1099
1100 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1101 target->drawIndexed(kTriangles_PrimitiveType,
1102 0, 0, 16, aaStrokeRectIndexCount());
1103}
1104
reed@google.com20efde72011-05-09 17:00:02 +00001105/**
1106 * Returns true if the rects edges are integer-aligned.
1107 */
1108static bool isIRect(const GrRect& r) {
1109 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1110 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1111}
1112
bsalomon@google.com205d4602011-04-25 12:43:45 +00001113static bool apply_aa_to_rect(GrDrawTarget* target,
1114 GrGpu* gpu,
1115 const GrPaint& paint,
1116 const GrRect& rect,
1117 GrScalar width,
1118 const GrMatrix* matrix,
1119 GrMatrix* combinedMatrix,
1120 GrRect* devRect) {
1121 // we use a simple alpha ramp to do aa on axis-aligned rects
1122 // do AA with alpha ramp if the caller requested AA, the rect
1123 // will be axis-aligned,the render target is not
1124 // multisampled, and the rect won't land on integer coords.
1125
1126 if (!paint.fAntiAlias) {
1127 return false;
1128 }
1129
1130 if (target->getRenderTarget()->isMultisampled()) {
1131 return false;
1132 }
1133
1134 if (0 == width && gpu->supportsAALines()) {
1135 return false;
1136 }
1137
1138 if (!target->getViewMatrix().preservesAxisAlignment()) {
1139 return false;
1140 }
1141
1142 if (NULL != matrix &&
1143 !matrix->preservesAxisAlignment()) {
1144 return false;
1145 }
1146
1147 *combinedMatrix = target->getViewMatrix();
1148 if (NULL != matrix) {
1149 combinedMatrix->preConcat(*matrix);
1150 GrAssert(combinedMatrix->preservesAxisAlignment());
1151 }
1152
1153 combinedMatrix->mapRect(devRect, rect);
1154 devRect->sort();
1155
1156 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001157 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001158 } else {
1159 return true;
1160 }
1161}
1162
bsalomon@google.com27847de2011-02-22 20:59:41 +00001163void GrContext::drawRect(const GrPaint& paint,
1164 const GrRect& rect,
1165 GrScalar width,
1166 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001167 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001168
1169 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001170 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001171
bsalomon@google.com205d4602011-04-25 12:43:45 +00001172 GrRect devRect = rect;
1173 GrMatrix combinedMatrix;
1174 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1175 &combinedMatrix, &devRect);
1176
1177 if (doAA) {
1178 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001179 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001180 GrMatrix inv;
1181 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001182 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001183 }
1184 }
1185 target->setViewMatrix(GrMatrix::I());
1186 if (width >= 0) {
1187 GrVec strokeSize;;
1188 if (width > 0) {
1189 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001190 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001191 strokeSize.setAbs(strokeSize);
1192 } else {
1193 strokeSize.set(GR_Scalar1, GR_Scalar1);
1194 }
1195 strokeAARect(target, paint, devRect, strokeSize);
1196 } else {
1197 fillAARect(target, paint, devRect);
1198 }
1199 return;
1200 }
1201
bsalomon@google.com27847de2011-02-22 20:59:41 +00001202 if (width >= 0) {
1203 // TODO: consider making static vertex buffers for these cases.
1204 // Hairline could be done by just adding closing vertex to
1205 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001206 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1207
bsalomon@google.com27847de2011-02-22 20:59:41 +00001208 static const int worstCaseVertCount = 10;
1209 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1210
1211 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001212 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001213 return;
1214 }
1215
1216 GrPrimitiveType primType;
1217 int vertCount;
1218 GrPoint* vertex = geo.positions();
1219
1220 if (width > 0) {
1221 vertCount = 10;
1222 primType = kTriangleStrip_PrimitiveType;
1223 setStrokeRectStrip(vertex, rect, width);
1224 } else {
1225 // hairline
1226 vertCount = 5;
1227 primType = kLineStrip_PrimitiveType;
1228 vertex[0].set(rect.fLeft, rect.fTop);
1229 vertex[1].set(rect.fRight, rect.fTop);
1230 vertex[2].set(rect.fRight, rect.fBottom);
1231 vertex[3].set(rect.fLeft, rect.fBottom);
1232 vertex[4].set(rect.fLeft, rect.fTop);
1233 }
1234
1235 GrDrawTarget::AutoViewMatrixRestore avmr;
1236 if (NULL != matrix) {
1237 avmr.set(target);
1238 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001239 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001240 }
1241
1242 target->drawNonIndexed(primType, 0, vertCount);
1243 } else {
1244 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001245 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001246 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1247 if (NULL == sqVB) {
1248 GrPrintf("Failed to create static rect vb.\n");
1249 return;
1250 }
1251 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001252 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1253 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001254 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001255 0, rect.height(), rect.fTop,
1256 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001257
1258 if (NULL != matrix) {
1259 m.postConcat(*matrix);
1260 }
1261
1262 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001263 target->preConcatSamplerMatrices(stageMask, m);
1264
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1266 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001267 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001268 #endif
1269 }
1270}
1271
1272void GrContext::drawRectToRect(const GrPaint& paint,
1273 const GrRect& dstRect,
1274 const GrRect& srcRect,
1275 const GrMatrix* dstMatrix,
1276 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001277 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001278
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001279 // srcRect refers to paint's first texture
1280 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001281 drawRect(paint, dstRect, -1, dstMatrix);
1282 return;
1283 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001284
bsalomon@google.com27847de2011-02-22 20:59:41 +00001285 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1286
1287#if GR_STATIC_RECT_VB
1288 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001289
1290 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001291 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1292
1293 GrMatrix m;
1294
1295 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1296 0, dstRect.height(), dstRect.fTop,
1297 0, 0, GrMatrix::I()[8]);
1298 if (NULL != dstMatrix) {
1299 m.postConcat(*dstMatrix);
1300 }
1301 target->preConcatViewMatrix(m);
1302
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001303 // srcRect refers to first stage
1304 int otherStageMask = paint.getActiveStageMask() &
1305 (~(1 << GrPaint::kFirstTextureStage));
1306 if (otherStageMask) {
1307 target->preConcatSamplerMatrices(otherStageMask, m);
1308 }
1309
bsalomon@google.com27847de2011-02-22 20:59:41 +00001310 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1311 0, srcRect.height(), srcRect.fTop,
1312 0, 0, GrMatrix::I()[8]);
1313 if (NULL != srcMatrix) {
1314 m.postConcat(*srcMatrix);
1315 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001316 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001318 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1319 if (NULL == sqVB) {
1320 GrPrintf("Failed to create static rect vb.\n");
1321 return;
1322 }
1323 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1325#else
1326
1327 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001328#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001329 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001330#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1332#endif
1333
1334 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1335 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1336 srcRects[0] = &srcRect;
1337 srcMatrices[0] = srcMatrix;
1338
1339 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1340#endif
1341}
1342
1343void GrContext::drawVertices(const GrPaint& paint,
1344 GrPrimitiveType primitiveType,
1345 int vertexCount,
1346 const GrPoint positions[],
1347 const GrPoint texCoords[],
1348 const GrColor colors[],
1349 const uint16_t indices[],
1350 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001351 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001352
1353 GrDrawTarget::AutoReleaseGeometry geo;
1354
1355 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1356
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001357 bool hasTexCoords[GrPaint::kTotalStages] = {
1358 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1359 0 // remaining stages use positions
1360 };
1361
1362 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001363
1364 if (NULL != colors) {
1365 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001366 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001367 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001368
1369 if (sizeof(GrPoint) != vertexSize) {
1370 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001371 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372 return;
1373 }
1374 int texOffsets[GrDrawTarget::kMaxTexCoords];
1375 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001376 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1377 texOffsets,
1378 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379 void* curVertex = geo.vertices();
1380
1381 for (int i = 0; i < vertexCount; ++i) {
1382 *((GrPoint*)curVertex) = positions[i];
1383
1384 if (texOffsets[0] > 0) {
1385 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1386 }
1387 if (colorOffset > 0) {
1388 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1389 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001390 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001391 }
1392 } else {
1393 target->setVertexSourceToArray(layout, positions, vertexCount);
1394 }
1395
bsalomon@google.com91958362011-06-13 17:58:13 +00001396 // we don't currently apply offscreen AA to this path. Need improved
1397 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001398
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001399 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001400 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001401 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001402 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001403 target->drawNonIndexed(primitiveType, 0, vertexCount);
1404 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405}
1406
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001407///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001408
reed@google.com07f3ee12011-05-16 17:21:57 +00001409void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1410 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411
bsalomon@google.com27847de2011-02-22 20:59:41 +00001412 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comee435122011-07-01 14:57:55 +00001413 GrPathRenderer* pr = this->getPathRenderer(path, fill);
1414 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1415 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001417 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001418 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001419
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001420 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001421
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001422 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001423 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1424 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001425 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001426 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001427 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001428 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001429 return;
1430 }
1431 }
reed@google.com70c136e2011-06-03 19:51:26 +00001432
reed@google.com07f3ee12011-05-16 17:21:57 +00001433 GrRect pathBounds = path.getBounds();
1434 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001435 if (NULL != translate) {
1436 pathBounds.offset(*translate);
1437 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001438 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001439 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001440 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001441 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001442 return;
1443 }
1444 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001445 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001446 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1447 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001448 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1449 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1450 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001451 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001452 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1453 }
1454 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001455 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001456 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001457 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1458 GrRect rect;
1459 if (clipIBounds.fTop < bound.fTop) {
1460 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1461 clipIBounds.fRight, bound.fTop);
1462 target->drawSimpleRect(rect, NULL, stageMask);
1463 }
1464 if (clipIBounds.fLeft < bound.fLeft) {
1465 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1466 bound.fLeft, bound.fBottom);
1467 target->drawSimpleRect(rect, NULL, stageMask);
1468 }
1469 if (clipIBounds.fRight > bound.fRight) {
1470 rect.setLTRB(bound.fRight, bound.fTop,
1471 clipIBounds.fRight, bound.fBottom);
1472 target->drawSimpleRect(rect, NULL, stageMask);
1473 }
1474 if (clipIBounds.fBottom > bound.fBottom) {
1475 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1476 clipIBounds.fRight, clipIBounds.fBottom);
1477 target->drawSimpleRect(rect, NULL, stageMask);
1478 }
1479 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001480 return;
1481 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001482 }
1483 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001484}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001485
bsalomon@google.com27847de2011-02-22 20:59:41 +00001486////////////////////////////////////////////////////////////////////////////////
1487
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001488void GrContext::flush(int flagsBitfield) {
1489 if (kDiscard_FlushBit & flagsBitfield) {
1490 fDrawBuffer->reset();
1491 } else {
1492 flushDrawBuffer();
1493 }
1494
1495 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001496 fGpu->forceRenderTargetFlush();
1497 }
1498}
1499
1500void GrContext::flushText() {
1501 if (kText_DrawCategory == fLastDrawCategory) {
1502 flushDrawBuffer();
1503 }
1504}
1505
1506void GrContext::flushDrawBuffer() {
1507#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001508 if (fDrawBuffer) {
1509 fDrawBuffer->playback(fGpu);
1510 fDrawBuffer->reset();
1511 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001512#endif
1513}
1514
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001515bool GrContext::readTexturePixels(GrTexture* texture,
1516 int left, int top, int width, int height,
1517 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001518 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001519
1520 // TODO: code read pixels for textures that aren't rendertargets
1521
1522 this->flush();
1523 GrRenderTarget* target = texture->asRenderTarget();
1524 if (NULL != target) {
1525 return fGpu->readPixels(target,
1526 left, top, width, height,
1527 config, buffer);
1528 } else {
1529 return false;
1530 }
1531}
1532
1533bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1534 int left, int top, int width, int height,
1535 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001536 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001537 uint32_t flushFlags = 0;
1538 if (NULL == target) {
1539 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1540 }
1541
1542 this->flush(flushFlags);
1543 return fGpu->readPixels(target,
1544 left, top, width, height,
1545 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001546}
1547
1548void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001549 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001550 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001551 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001552
1553 // TODO: when underlying api has a direct way to do this we should use it
1554 // (e.g. glDrawPixels on desktop GL).
1555
bsalomon@google.com5c638652011-07-18 19:31:59 +00001556 this->flush(true);
1557
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001558 const GrTextureDesc desc = {
1559 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001560 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001561 GrAutoScratchTexture ast(this, desc);
1562 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001563 if (NULL == texture) {
1564 return;
1565 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001566 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001567
bsalomon@google.com27847de2011-02-22 20:59:41 +00001568 GrDrawTarget::AutoStateRestore asr(fGpu);
1569
1570 GrMatrix matrix;
1571 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1572 fGpu->setViewMatrix(matrix);
1573
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001574 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001575 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1576 fGpu->setAlpha(0xFF);
1577 fGpu->setBlendFunc(kOne_BlendCoeff,
1578 kZero_BlendCoeff);
1579 fGpu->setTexture(0, texture);
1580
1581 GrSamplerState sampler;
1582 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001583 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001584 sampler.setMatrix(matrix);
1585 fGpu->setSamplerState(0, sampler);
1586
1587 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1588 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001589 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001590 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1591 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001592 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001593 return;
1594 }
1595 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1596 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1597}
1598////////////////////////////////////////////////////////////////////////////////
1599
1600void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001601
1602 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1603 int s = i + GrPaint::kFirstTextureStage;
1604 target->setTexture(s, paint.getTexture(i));
1605 target->setSamplerState(s, *paint.getTextureSampler(i));
1606 }
1607
1608 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1609
1610 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1611 int s = i + GrPaint::kFirstMaskStage;
1612 target->setTexture(s, paint.getMask(i));
1613 target->setSamplerState(s, *paint.getMaskSampler(i));
1614 }
1615
bsalomon@google.com27847de2011-02-22 20:59:41 +00001616 target->setColor(paint.fColor);
1617
1618 if (paint.fDither) {
1619 target->enableState(GrDrawTarget::kDither_StateBit);
1620 } else {
1621 target->disableState(GrDrawTarget::kDither_StateBit);
1622 }
1623 if (paint.fAntiAlias) {
1624 target->enableState(GrDrawTarget::kAntialias_StateBit);
1625 } else {
1626 target->disableState(GrDrawTarget::kAntialias_StateBit);
1627 }
1628 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001629 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001630}
1631
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001632GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001633 DrawCategory category) {
1634 if (category != fLastDrawCategory) {
1635 flushDrawBuffer();
1636 fLastDrawCategory = category;
1637 }
1638 SetPaint(paint, fGpu);
1639 GrDrawTarget* target = fGpu;
1640 switch (category) {
1641 case kText_DrawCategory:
1642#if DEFER_TEXT_RENDERING
1643 target = fDrawBuffer;
1644 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1645#else
1646 target = fGpu;
1647#endif
1648 break;
1649 case kUnbuffered_DrawCategory:
1650 target = fGpu;
1651 break;
1652 case kBuffered_DrawCategory:
1653 target = fDrawBuffer;
1654 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1655 break;
1656 }
1657 return target;
1658}
1659
1660////////////////////////////////////////////////////////////////////////////////
1661
bsalomon@google.com27847de2011-02-22 20:59:41 +00001662void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001663 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001664 fGpu->setRenderTarget(target);
1665}
1666
1667GrRenderTarget* GrContext::getRenderTarget() {
1668 return fGpu->getRenderTarget();
1669}
1670
1671const GrRenderTarget* GrContext::getRenderTarget() const {
1672 return fGpu->getRenderTarget();
1673}
1674
1675const GrMatrix& GrContext::getMatrix() const {
1676 return fGpu->getViewMatrix();
1677}
1678
1679void GrContext::setMatrix(const GrMatrix& m) {
1680 fGpu->setViewMatrix(m);
1681}
1682
1683void GrContext::concatMatrix(const GrMatrix& m) const {
1684 fGpu->preConcatViewMatrix(m);
1685}
1686
1687static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1688 intptr_t mask = 1 << shift;
1689 if (pred) {
1690 bits |= mask;
1691 } else {
1692 bits &= ~mask;
1693 }
1694 return bits;
1695}
1696
1697void GrContext::resetStats() {
1698 fGpu->resetStats();
1699}
1700
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001701const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001702 return fGpu->getStats();
1703}
1704
1705void GrContext::printStats() const {
1706 fGpu->printStats();
1707}
1708
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001709GrContext::GrContext(GrGpu* gpu) :
1710 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1711 gpu->supportsStencilWrapOps()) {
1712
bsalomon@google.com27847de2011-02-22 20:59:41 +00001713 fGpu = gpu;
1714 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001715 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001716
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001717 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1718 fGpu->setClipPathRenderer(fCustomPathRenderer);
1719
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001720 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1721 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001722 fFontCache = new GrFontCache(fGpu);
1723
1724 fLastDrawCategory = kUnbuffered_DrawCategory;
1725
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001726 fDrawBuffer = NULL;
1727 fDrawBufferVBAllocPool = NULL;
1728 fDrawBufferIBAllocPool = NULL;
1729
bsalomon@google.com205d4602011-04-25 12:43:45 +00001730 fAAFillRectIndexBuffer = NULL;
1731 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001732
1733 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1734 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1735 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1736 }
1737 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001738
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001739 this->setupDrawBuffer();
1740}
1741
1742void GrContext::setupDrawBuffer() {
1743
1744 GrAssert(NULL == fDrawBuffer);
1745 GrAssert(NULL == fDrawBufferVBAllocPool);
1746 GrAssert(NULL == fDrawBufferIBAllocPool);
1747
bsalomon@google.com27847de2011-02-22 20:59:41 +00001748#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001749 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001750 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001751 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1752 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001753 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001754 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001755 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001756 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1757
1758 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1759 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001760#endif
1761
1762#if BATCH_RECT_TO_RECT
1763 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1764#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001765}
1766
bsalomon@google.com27847de2011-02-22 20:59:41 +00001767GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1768 GrDrawTarget* target;
1769#if DEFER_TEXT_RENDERING
1770 target = prepareToDraw(paint, kText_DrawCategory);
1771#else
1772 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1773#endif
1774 SetPaint(paint, target);
1775 return target;
1776}
1777
1778const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1779 return fGpu->getQuadIndexBuffer();
1780}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001781
bsalomon@google.comee435122011-07-01 14:57:55 +00001782GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001783 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001784 if (NULL != fCustomPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +00001785 fCustomPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001786 return fCustomPathRenderer;
1787 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +00001788 GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001789 return &fDefaultPathRenderer;
1790 }
1791}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001792
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001793void GrContext::convolveInX(GrTexture* texture,
1794 const SkRect& rect,
1795 const float* kernel,
1796 int kernelWidth) {
1797 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1798 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1799}
1800
1801void GrContext::convolveInY(GrTexture* texture,
1802 const SkRect& rect,
1803 const float* kernel,
1804 int kernelWidth) {
1805 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1806 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1807}
1808
1809void GrContext::convolve(GrTexture* texture,
1810 const SkRect& rect,
1811 float imageIncrement[2],
1812 const float* kernel,
1813 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001814 GrDrawTarget::AutoStateRestore asr(fGpu);
1815 GrMatrix sampleM;
1816 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1817 GrSamplerState::kClamp_WrapMode,
1818 GrSamplerState::kConvolution_Filter);
1819 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001820 sampleM.setScale(GR_Scalar1 / texture->width(),
1821 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001822 sampler.setMatrix(sampleM);
1823 fGpu->setSamplerState(0, sampler);
1824 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001825 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001826 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001827 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1828}