blob: 4ebe00c0b381471a2db63063d9a44d44bd24d826 [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"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000019#include "GrTextStrike.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000020#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000021
bsalomon@google.com91958362011-06-13 17:58:13 +000022// Using MSAA seems to be slower for some yet unknown reason.
23#define PREFER_MSAA_OFFSCREEN_AA 0
24#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000025
bsalomon@google.com27847de2011-02-22 20:59:41 +000026#define DEFER_TEXT_RENDERING 1
27
28#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
29
30static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
31static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
32
33static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
34static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
35
36// We are currently only batching Text and drawRectToRect, both
37// of which use the quad index buffer.
38static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
39static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
40
bsalomon@google.com05ef5102011-05-02 21:14:59 +000041GrContext* GrContext::Create(GrEngine engine,
42 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000043 GrContext* ctx = NULL;
44 GrGpu* fGpu = GrGpu::Create(engine, context3D);
45 if (NULL != fGpu) {
46 ctx = new GrContext(fGpu);
47 fGpu->unref();
48 }
49 return ctx;
50}
51
52GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000053 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000054}
55
56GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000057 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000058 delete fTextureCache;
59 delete fFontCache;
60 delete fDrawBuffer;
61 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000062 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000063 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000064 GrSafeUnref(fAAFillRectIndexBuffer);
65 GrSafeUnref(fAAStrokeRectIndexBuffer);
66 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000067}
68
bsalomon@google.com8fe72472011-03-30 21:26:44 +000069void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000070 contextDestroyed();
71 this->setupDrawBuffer();
72}
73
74void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000075 // abandon first to so destructors
76 // don't try to free the resources in the API.
77 fGpu->abandonResources();
78
bsalomon@google.com8fe72472011-03-30 21:26:44 +000079 delete fDrawBuffer;
80 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000081
bsalomon@google.com8fe72472011-03-30 21:26:44 +000082 delete fDrawBufferVBAllocPool;
83 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000084
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBufferIBAllocPool;
86 fDrawBufferIBAllocPool = NULL;
87
bsalomon@google.com205d4602011-04-25 12:43:45 +000088 GrSafeSetNull(fAAFillRectIndexBuffer);
89 GrSafeSetNull(fAAStrokeRectIndexBuffer);
90
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 fTextureCache->removeAll();
92 fFontCache->freeAll();
93 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +000094}
95
96void GrContext::resetContext() {
97 fGpu->markContextDirty();
98}
99
100void GrContext::freeGpuResources() {
101 this->flush();
102 fTextureCache->removeAll();
103 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000104}
105
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000106////////////////////////////////////////////////////////////////////////////////
107
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000108int GrContext::PaintStageVertexLayoutBits(
109 const GrPaint& paint,
110 const bool hasTexCoords[GrPaint::kTotalStages]) {
111 int stageMask = paint.getActiveStageMask();
112 int layout = 0;
113 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
114 if ((1 << i) & stageMask) {
115 if (NULL != hasTexCoords && hasTexCoords[i]) {
116 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
117 } else {
118 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
119 }
120 }
121 }
122 return layout;
123}
124
125
126////////////////////////////////////////////////////////////////////////////////
127
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000128enum {
129 kNPOTBit = 0x1,
130 kFilterBit = 0x2,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000131 kScratchBit = 0x4,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000132};
133
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000134GrTexture* GrContext::TextureCacheEntry::texture() const {
135 if (NULL == fEntry) {
136 return NULL;
137 } else {
138 return (GrTexture*) fEntry->resource();
139 }
140}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000141
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000142namespace {
143// returns true if this is a "special" texture because of gpu NPOT limitations
144bool gen_texture_key_values(const GrGpu* gpu,
145 const GrSamplerState& sampler,
146 GrContext::TextureKey clientKey,
147 int width,
148 int height,
149 bool scratch,
150 uint32_t v[4]) {
151 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
152 // we assume we only need 16 bits of width and height
153 // assert that texture creation will fail anyway if this assumption
154 // would cause key collisions.
155 GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
156 v[0] = clientKey & 0xffffffffUL;
157 v[1] = (clientKey >> 32) & 0xffffffffUL;
158 v[2] = width | (height << 16);
159
160 v[3] = 0;
161 if (!gpu->npotTextureTileSupport()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000162 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
163
164 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
165 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
166
167 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000168 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000169 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000170 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000171 }
172 }
173 }
174
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000175 if (scratch) {
176 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000177 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000178
179 return v[3] & kNPOTBit;
180}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000181}
182
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000183GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
184 int width,
185 int height,
186 const GrSamplerState& sampler) {
187 uint32_t v[4];
188 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
189 GrResourceKey resourceKey(v);
190 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000191}
192
193static void stretchImage(void* dst,
194 int dstW,
195 int dstH,
196 void* src,
197 int srcW,
198 int srcH,
199 int bpp) {
200 GrFixed dx = (srcW << 16) / dstW;
201 GrFixed dy = (srcH << 16) / dstH;
202
203 GrFixed y = dy >> 1;
204
205 int dstXLimit = dstW*bpp;
206 for (int j = 0; j < dstH; ++j) {
207 GrFixed x = dx >> 1;
208 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
209 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
210 for (int i = 0; i < dstXLimit; i += bpp) {
211 memcpy((uint8_t*) dstRow + i,
212 (uint8_t*) srcRow + (x>>16)*bpp,
213 bpp);
214 x += dx;
215 }
216 y += dy;
217 }
218}
219
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000220GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000221 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000222 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000223 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000224 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000225
226#if GR_DUMP_TEXTURE_UPLOAD
227 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
228#endif
229
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000230 TextureCacheEntry entry;
231 uint32_t v[4];
232 bool special = gen_texture_key_values(fGpu, sampler, key,
233 desc.fWidth, desc.fHeight, false, v);
234 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000235
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000236 if (special) {
237 TextureCacheEntry clampEntry =
238 findAndLockTexture(key, desc.fWidth, desc.fHeight,
239 GrSamplerState::ClampNoFilter());
240
241 if (NULL == clampEntry.texture()) {
242 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000243 GrSamplerState::ClampNoFilter(),
244 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000245 GrAssert(NULL != clampEntry.texture());
246 if (NULL == clampEntry.texture()) {
247 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000248 }
249 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000250 GrTextureDesc rtDesc = desc;
251 rtDesc.fFlags = rtDesc.fFlags |
252 kRenderTarget_GrTextureFlagBit |
253 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000254 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
255 fGpu->minRenderTargetWidth()));
256 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
257 fGpu->minRenderTargetHeight()));
258
259 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
260
261 if (NULL != texture) {
262 GrDrawTarget::AutoStateRestore asr(fGpu);
263 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000264 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000265 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000266 fGpu->setViewMatrix(GrMatrix::I());
267 fGpu->setAlpha(0xff);
268 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
269 fGpu->disableState(GrDrawTarget::kDither_StateBit |
270 GrDrawTarget::kClip_StateBit |
271 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000272 GrSamplerState::Filter filter;
273 // if filtering is not desired then we want to ensure all
274 // texels in the resampled image are copies of texels from
275 // the original.
276 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
277 filter = GrSamplerState::kNearest_Filter;
278 } else {
279 filter = GrSamplerState::kBilinear_Filter;
280 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000281 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
282 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000283 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000284 fGpu->setSamplerState(0, stretchSampler);
285
286 static const GrVertexLayout layout =
287 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
288 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
289
290 if (arg.succeeded()) {
291 GrPoint* verts = (GrPoint*) arg.vertices();
292 verts[0].setIRectFan(0, 0,
293 texture->width(),
294 texture->height(),
295 2*sizeof(GrPoint));
296 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
297 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
298 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000299 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000300 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000301 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000302 } else {
303 // TODO: Our CPU stretch doesn't filter. But we create separate
304 // stretched textures when the sampler state is either filtered or
305 // not. Either implement filtered stretch blit on CPU or just create
306 // one when FBO case fails.
307
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000308 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000309 // no longer need to clamp at min RT size.
310 rtDesc.fWidth = GrNextPow2(desc.fWidth);
311 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000312 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000313 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000314 rtDesc.fWidth *
315 rtDesc.fHeight);
316 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
317 srcData, desc.fWidth, desc.fHeight, bpp);
318
319 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
320
321 GrTexture* texture = fGpu->createTexture(rtDesc,
322 stretchedPixels.get(),
323 stretchedRowBytes);
324 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000325 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000326 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000327 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000328
329 } else {
330 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
331 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000332 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000333 }
334 }
335 return entry;
336}
337
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000338namespace {
339inline void gen_scratch_tex_key_values(const GrGpu* gpu,
340 const GrTextureDesc& desc,
341 uint32_t v[4]) {
342 // Instead of a client-provided key of the texture contents
343 // we create a key of from the descriptor.
344 GrContext::TextureKey descKey = desc.fAALevel |
345 (desc.fFlags << 8) |
346 ((uint64_t) desc.fFormat << 32);
347 // this code path isn't friendly to tiling with NPOT restricitons
348 // We just pass ClampNoFilter()
349 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
350 desc.fWidth, desc.fHeight, true, v);
351}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000352}
353
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000354GrContext::TextureCacheEntry GrContext::lockScratchTexture(
355 const GrTextureDesc& inDesc,
356 ScratchTexMatch match) {
357
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000358 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000359 if (kExact_ScratchTexMatch != match) {
360 // bin by pow2 with a reasonable min
361 static const int MIN_SIZE = 256;
362 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
363 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
364 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000365
366 uint32_t p0 = desc.fFormat;
367 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
368
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000369 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000370 int origWidth = desc.fWidth;
371 int origHeight = desc.fHeight;
372 bool doubledW = false;
373 bool doubledH = false;
374
375 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000376 uint32_t v[4];
377 gen_scratch_tex_key_values(fGpu, desc, v);
378 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000379 entry = fTextureCache->findAndLock(key);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000380 // if we miss, relax the fit of the flags...
381 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000382 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000383 break;
384 }
385 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
386 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
387 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
388 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
389 } else if (!doubledW) {
390 desc.fFlags = inDesc.fFlags;
391 desc.fWidth *= 2;
392 doubledW = true;
393 } else if (!doubledH) {
394 desc.fFlags = inDesc.fFlags;
395 desc.fWidth = origWidth;
396 desc.fHeight *= 2;
397 doubledH = true;
398 } else {
399 break;
400 }
401
402 } while (true);
403
404 if (NULL == entry) {
405 desc.fFlags = inDesc.fFlags;
406 desc.fWidth = origWidth;
407 desc.fHeight = origHeight;
408 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
409 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000410 uint32_t v[4];
411 gen_scratch_tex_key_values(fGpu, desc, v);
412 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000413 entry = fTextureCache->createAndLock(key, texture);
414 }
415 }
416
417 // If the caller gives us the same desc/sampler twice we don't want
418 // to return the same texture the second time (unless it was previously
419 // released). So we detach the entry from the cache and reattach at release.
420 if (NULL != entry) {
421 fTextureCache->detach(entry);
422 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000423 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000424}
425
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000426void GrContext::unlockTexture(TextureCacheEntry entry) {
427 // If this is a scratch texture we detached it from the cache
428 // while it was locked (to avoid two callers simultaneously getting
429 // the same texture).
430 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
431 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000432 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000433 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000434 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000435}
436
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000437GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000438 void* srcData,
439 size_t rowBytes) {
440 return fGpu->createTexture(desc, srcData, rowBytes);
441}
442
443void GrContext::getTextureCacheLimits(int* maxTextures,
444 size_t* maxTextureBytes) const {
445 fTextureCache->getLimits(maxTextures, maxTextureBytes);
446}
447
448void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
449 fTextureCache->setLimits(maxTextures, maxTextureBytes);
450}
451
bsalomon@google.com91958362011-06-13 17:58:13 +0000452int GrContext::getMaxTextureSize() const {
453 return fGpu->maxTextureSize();
454}
455
456int GrContext::getMaxRenderTargetSize() const {
457 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000458}
459
460///////////////////////////////////////////////////////////////////////////////
461
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000462GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
463 // validate flags here so that GrGpu subclasses don't have to check
464 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
465 0 != desc.fRenderTargetFlags) {
466 return NULL;
467 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000468#if GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000469 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
470 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
471 return NULL;
472 }
473 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
474 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
475 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
476 return NULL;
477 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000478#else
479 if (desc.fSampleCnt &&
480 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
481 return NULL;
482 }
483 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
484 desc.fSampleCnt &&
485 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
486 return NULL;
487 }
488#endif
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000489 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000490}
491
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000492GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000493 return fGpu->createRenderTargetFrom3DApiState();
494}
495
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000496///////////////////////////////////////////////////////////////////////////////
497
bsalomon@google.com27847de2011-02-22 20:59:41 +0000498bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
499 int width, int height) {
500 if (!fGpu->supports8BitPalette()) {
501 return false;
502 }
503
504
505 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
506
507 if (!isPow2) {
508 if (!fGpu->npotTextureSupport()) {
509 return false;
510 }
511
512 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
513 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
514 if (tiled && !fGpu->npotTextureTileSupport()) {
515 return false;
516 }
517 }
518 return true;
519}
520
521////////////////////////////////////////////////////////////////////////////////
522
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000523const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
524
bsalomon@google.com27847de2011-02-22 20:59:41 +0000525void GrContext::setClip(const GrClip& clip) {
526 fGpu->setClip(clip);
527 fGpu->enableState(GrDrawTarget::kClip_StateBit);
528}
529
530void GrContext::setClip(const GrIRect& rect) {
531 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000532 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000533 fGpu->setClip(clip);
534}
535
536////////////////////////////////////////////////////////////////////////////////
537
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000538void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000539 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000540 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000541}
542
543void GrContext::drawPaint(const GrPaint& paint) {
544 // set rect to be big enough to fill the space, but not super-huge, so we
545 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000546 GrRect r;
547 r.setLTRB(0, 0,
548 GrIntToScalar(getRenderTarget()->width()),
549 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000550 GrMatrix inverse;
551 if (fGpu->getViewInverse(&inverse)) {
552 inverse.mapRect(&r);
553 } else {
554 GrPrintf("---- fGpu->getViewInverse failed\n");
555 }
556 this->drawRect(paint, r);
557}
558
bsalomon@google.com205d4602011-04-25 12:43:45 +0000559////////////////////////////////////////////////////////////////////////////////
560
bsalomon@google.com91958362011-06-13 17:58:13 +0000561struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000562 enum Downsample {
563 k4x4TwoPass_Downsample,
564 k4x4SinglePass_Downsample,
565 kFSAA_Downsample
566 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000567 int fTileSizeX;
568 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000569 int fTileCountX;
570 int fTileCountY;
571 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000572 GrAutoScratchTexture fOffscreen0;
573 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000574 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000575 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000576};
577
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000578bool GrContext::doOffscreenAA(GrDrawTarget* target,
579 const GrPaint& paint,
580 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000581#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000582 return false;
583#else
584 if (!paint.fAntiAlias) {
585 return false;
586 }
587 if (isLines && fGpu->supportsAALines()) {
588 return false;
589 }
590 if (target->getRenderTarget()->isMultisampled()) {
591 return false;
592 }
593 // we have to be sure that the blend equation is expressible
594 // as simple src / dst coeffecients when the source
595 // is already modulated by the coverage fraction.
596 // We could use dual-source blending to get the correct per-pixel
597 // dst coeffecient for the remaining cases.
598 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
599 kOne_BlendCoeff != paint.fDstBlendCoeff &&
600 kISA_BlendCoeff != paint.fDstBlendCoeff) {
601 return false;
602 }
603 return true;
604#endif
605}
606
bsalomon@google.com91958362011-06-13 17:58:13 +0000607bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000608 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000609 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000610 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000611 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000612
613 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000614
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000615 GrAssert(NULL == record->fOffscreen0.texture());
616 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000617 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000618
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000619 int boundW = boundRect.width();
620 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000621
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000622 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000623
624 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
625 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
626
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000627 if (requireStencil) {
628 desc.fFlags = kRenderTarget_GrTextureFlagBit;
629 } else {
630 desc.fFlags = kRenderTarget_GrTextureFlagBit |
631 kNoStencil_GrTextureFlagBit;
632 }
633
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000634 desc.fFormat = kRGBA_8888_GrPixelConfig;
635
bsalomon@google.com91958362011-06-13 17:58:13 +0000636 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000637 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000638 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000639 desc.fAALevel = kMed_GrAALevel;
640 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000641 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
642 OffscreenRecord::k4x4SinglePass_Downsample :
643 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000644 record->fScale = OFFSCREEN_SSAA_SCALE;
645 // both downsample paths assume this
646 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000647 desc.fAALevel = kNone_GrAALevel;
648 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000649 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
650 // of simple circles?
651 if (pr) {
652 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
653 }
654
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000655 desc.fWidth *= record->fScale;
656 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000657 record->fOffscreen0.set(this, desc);
658 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000659 return false;
660 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000661 // the approximate lookup might have given us some slop space, might as well
662 // use it when computing the tiles size.
663 // these are scale values, will adjust after considering
664 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000665 record->fTileSizeX = record->fOffscreen0.texture()->width();
666 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000667
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000668 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000669 desc.fWidth /= 2;
670 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000671 record->fOffscreen1.set(this, desc);
672 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000673 return false;
674 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000675 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000676 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000677 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000678 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000679 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000680 record->fTileSizeX /= record->fScale;
681 record->fTileSizeY /= record->fScale;
682
683 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
684 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
685
tomhudson@google.com237a4612011-07-19 15:44:00 +0000686 record->fClip = target->getClip();
687
bsalomon@google.com91958362011-06-13 17:58:13 +0000688 target->saveCurrentDrawState(&record->fSavedState);
689 return true;
690}
691
692void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
693 const GrIRect& boundRect,
694 int tileX, int tileY,
695 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000696
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000697 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000698 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000699
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000700 GrPaint tempPaint;
701 tempPaint.reset();
702 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000703 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000704
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000705 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000706 int left = boundRect.fLeft + tileX * record->fTileSizeX;
707 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000708 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000709 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000710 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000711 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000712 target->postConcatViewMatrix(scaleM);
713
bsalomon@google.com91958362011-06-13 17:58:13 +0000714 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000715 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000716 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000717 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000718 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
719 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000720 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000721#if 0
722 // visualize tile boundaries by setting edges of offscreen to white
723 // and interior to tranparent. black.
724 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000725
bsalomon@google.com91958362011-06-13 17:58:13 +0000726 static const int gOffset = 2;
727 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
728 record->fScale * w - gOffset,
729 record->fScale * h - gOffset);
730 target->clear(&clear2, 0x0);
731#else
732 target->clear(&clear, 0x0);
733#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000734}
735
bsalomon@google.com91958362011-06-13 17:58:13 +0000736void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000737 const GrPaint& paint,
738 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000739 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000740 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000741 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000742 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000743 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000744 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000745 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
746 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000747 tileRect.fRight = (tileX == record->fTileCountX-1) ?
748 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000749 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000750 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
751 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000752 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000753
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000754 GrSamplerState::Filter filter;
755 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
756 filter = GrSamplerState::k4x4Downsample_Filter;
757 } else {
758 filter = GrSamplerState::kBilinear_Filter;
759 }
760
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000761 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000762 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000763 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000764
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000765 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000766 int scale;
767
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000768 enum {
769 kOffscreenStage = GrPaint::kTotalStages,
770 };
771
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000772 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000773 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000774 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000775 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000776
777 // Do 2x2 downsample from first to second
778 target->setTexture(kOffscreenStage, src);
779 target->setRenderTarget(dst);
780 target->setViewMatrix(GrMatrix::I());
781 sampleM.setScale(scale * GR_Scalar1 / src->width(),
782 scale * GR_Scalar1 / src->height());
783 sampler.setMatrix(sampleM);
784 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000785 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
786 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000787 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
788
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000789 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000790 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000791 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000792 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000793 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000794 } else {
795 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
796 record->fDownsample);
797 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000798 }
799
bsalomon@google.com91958362011-06-13 17:58:13 +0000800 // setup for draw back to main RT, we use the original
801 // draw state setup by the caller plus an additional coverage
802 // stage to handle the AA resolve. Also, we use an identity
803 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000804 int stageMask = paint.getActiveStageMask();
805
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000806 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000807 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000808
809 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000810 GrMatrix invVM;
811 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000812 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000813 }
814 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000815 // This is important when tiling, otherwise second tile's
816 // pass 1 view matrix will be incorrect.
817 GrDrawTarget::AutoViewMatrixRestore avmr(target);
818
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000819 target->setViewMatrix(GrMatrix::I());
820
821 target->setTexture(kOffscreenStage, src);
822 sampleM.setScale(scale * GR_Scalar1 / src->width(),
823 scale * GR_Scalar1 / src->height());
824 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000825 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000826 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000827 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000828
reed@google.com20efde72011-05-09 17:00:02 +0000829 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000830 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000831 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000832 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000833}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000834
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000835void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
836 GrPathRenderer* pr,
837 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000838 if (pr) {
839 // Counterpart of scale() in prepareForOffscreenAA()
840 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
841 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000842 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000843}
844
845////////////////////////////////////////////////////////////////////////////////
846
bsalomon@google.com27847de2011-02-22 20:59:41 +0000847/* create a triangle strip that strokes the specified triangle. There are 8
848 unique vertices, but we repreat the last 2 to close up. Alternatively we
849 could use an indices array, and then only send 8 verts, but not sure that
850 would be faster.
851 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000852static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000853 GrScalar width) {
854 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000855 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000856
857 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
858 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
859 verts[2].set(rect.fRight - rad, rect.fTop + rad);
860 verts[3].set(rect.fRight + rad, rect.fTop - rad);
861 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
862 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
863 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
864 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
865 verts[8] = verts[0];
866 verts[9] = verts[1];
867}
868
bsalomon@google.com205d4602011-04-25 12:43:45 +0000869static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000870 // FIXME: This was copied from SkGpuDevice, seems like
871 // we should have already smeared a in caller if that
872 // is what is desired.
873 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000874 unsigned a = GrColorUnpackA(paint.fColor);
875 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000876 } else {
877 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000878 }
879}
880
881static void setInsetFan(GrPoint* pts, size_t stride,
882 const GrRect& r, GrScalar dx, GrScalar dy) {
883 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
884}
885
886static const uint16_t gFillAARectIdx[] = {
887 0, 1, 5, 5, 4, 0,
888 1, 2, 6, 6, 5, 1,
889 2, 3, 7, 7, 6, 2,
890 3, 0, 4, 4, 7, 3,
891 4, 5, 6, 6, 7, 4,
892};
893
894int GrContext::aaFillRectIndexCount() const {
895 return GR_ARRAY_COUNT(gFillAARectIdx);
896}
897
898GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
899 if (NULL == fAAFillRectIndexBuffer) {
900 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
901 false);
902 GrAssert(NULL != fAAFillRectIndexBuffer);
903#if GR_DEBUG
904 bool updated =
905#endif
906 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
907 sizeof(gFillAARectIdx));
908 GR_DEBUGASSERT(updated);
909 }
910 return fAAFillRectIndexBuffer;
911}
912
913static const uint16_t gStrokeAARectIdx[] = {
914 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
915 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
916 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
917 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
918
919 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
920 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
921 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
922 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
923
924 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
925 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
926 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
927 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
928};
929
930int GrContext::aaStrokeRectIndexCount() const {
931 return GR_ARRAY_COUNT(gStrokeAARectIdx);
932}
933
934GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
935 if (NULL == fAAStrokeRectIndexBuffer) {
936 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
937 false);
938 GrAssert(NULL != fAAStrokeRectIndexBuffer);
939#if GR_DEBUG
940 bool updated =
941#endif
942 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
943 sizeof(gStrokeAARectIdx));
944 GR_DEBUGASSERT(updated);
945 }
946 return fAAStrokeRectIndexBuffer;
947}
948
949void GrContext::fillAARect(GrDrawTarget* target,
950 const GrPaint& paint,
951 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000952 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
953 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000954
955 size_t vsize = GrDrawTarget::VertexSize(layout);
956
957 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
958
959 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
960
961 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
962 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
963
964 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
965 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
966
967 verts += sizeof(GrPoint);
968 for (int i = 0; i < 4; ++i) {
969 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
970 }
971
972 GrColor innerColor = getColorForMesh(paint);
973 verts += 4 * vsize;
974 for (int i = 0; i < 4; ++i) {
975 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
976 }
977
978 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
979
980 target->drawIndexed(kTriangles_PrimitiveType, 0,
981 0, 8, this->aaFillRectIndexCount());
982}
983
984void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
985 const GrRect& devRect, const GrVec& devStrokeSize) {
986 const GrScalar& dx = devStrokeSize.fX;
987 const GrScalar& dy = devStrokeSize.fY;
988 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
989 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
990
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000991 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
992 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000993
994 GrScalar spare;
995 {
996 GrScalar w = devRect.width() - dx;
997 GrScalar h = devRect.height() - dy;
998 spare = GrMin(w, h);
999 }
1000
1001 if (spare <= 0) {
1002 GrRect r(devRect);
1003 r.inset(-rx, -ry);
1004 fillAARect(target, paint, r);
1005 return;
1006 }
1007
1008 size_t vsize = GrDrawTarget::VertexSize(layout);
1009
1010 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
1011
1012 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1013
1014 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1015 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1016 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1017 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1018
1019 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1020 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1021 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1022 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + 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 < 8; ++i) {
1032 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1033 }
1034
1035 verts += 8 * vsize;
1036 for (int i = 0; i < 8; ++i) {
1037 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1038 }
1039
1040 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1041 target->drawIndexed(kTriangles_PrimitiveType,
1042 0, 0, 16, aaStrokeRectIndexCount());
1043}
1044
reed@google.com20efde72011-05-09 17:00:02 +00001045/**
1046 * Returns true if the rects edges are integer-aligned.
1047 */
1048static bool isIRect(const GrRect& r) {
1049 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1050 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1051}
1052
bsalomon@google.com205d4602011-04-25 12:43:45 +00001053static bool apply_aa_to_rect(GrDrawTarget* target,
1054 GrGpu* gpu,
1055 const GrPaint& paint,
1056 const GrRect& rect,
1057 GrScalar width,
1058 const GrMatrix* matrix,
1059 GrMatrix* combinedMatrix,
1060 GrRect* devRect) {
1061 // we use a simple alpha ramp to do aa on axis-aligned rects
1062 // do AA with alpha ramp if the caller requested AA, the rect
1063 // will be axis-aligned,the render target is not
1064 // multisampled, and the rect won't land on integer coords.
1065
1066 if (!paint.fAntiAlias) {
1067 return false;
1068 }
1069
1070 if (target->getRenderTarget()->isMultisampled()) {
1071 return false;
1072 }
1073
1074 if (0 == width && gpu->supportsAALines()) {
1075 return false;
1076 }
1077
1078 if (!target->getViewMatrix().preservesAxisAlignment()) {
1079 return false;
1080 }
1081
1082 if (NULL != matrix &&
1083 !matrix->preservesAxisAlignment()) {
1084 return false;
1085 }
1086
1087 *combinedMatrix = target->getViewMatrix();
1088 if (NULL != matrix) {
1089 combinedMatrix->preConcat(*matrix);
1090 GrAssert(combinedMatrix->preservesAxisAlignment());
1091 }
1092
1093 combinedMatrix->mapRect(devRect, rect);
1094 devRect->sort();
1095
1096 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001097 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001098 } else {
1099 return true;
1100 }
1101}
1102
bsalomon@google.com27847de2011-02-22 20:59:41 +00001103void GrContext::drawRect(const GrPaint& paint,
1104 const GrRect& rect,
1105 GrScalar width,
1106 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001107 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001108
1109 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001110 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001111
bsalomon@google.com205d4602011-04-25 12:43:45 +00001112 GrRect devRect = rect;
1113 GrMatrix combinedMatrix;
1114 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1115 &combinedMatrix, &devRect);
1116
1117 if (doAA) {
1118 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001119 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001120 GrMatrix inv;
1121 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001122 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001123 }
1124 }
1125 target->setViewMatrix(GrMatrix::I());
1126 if (width >= 0) {
1127 GrVec strokeSize;;
1128 if (width > 0) {
1129 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001130 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001131 strokeSize.setAbs(strokeSize);
1132 } else {
1133 strokeSize.set(GR_Scalar1, GR_Scalar1);
1134 }
1135 strokeAARect(target, paint, devRect, strokeSize);
1136 } else {
1137 fillAARect(target, paint, devRect);
1138 }
1139 return;
1140 }
1141
bsalomon@google.com27847de2011-02-22 20:59:41 +00001142 if (width >= 0) {
1143 // TODO: consider making static vertex buffers for these cases.
1144 // Hairline could be done by just adding closing vertex to
1145 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001146 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1147
bsalomon@google.com27847de2011-02-22 20:59:41 +00001148 static const int worstCaseVertCount = 10;
1149 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1150
1151 if (!geo.succeeded()) {
1152 return;
1153 }
1154
1155 GrPrimitiveType primType;
1156 int vertCount;
1157 GrPoint* vertex = geo.positions();
1158
1159 if (width > 0) {
1160 vertCount = 10;
1161 primType = kTriangleStrip_PrimitiveType;
1162 setStrokeRectStrip(vertex, rect, width);
1163 } else {
1164 // hairline
1165 vertCount = 5;
1166 primType = kLineStrip_PrimitiveType;
1167 vertex[0].set(rect.fLeft, rect.fTop);
1168 vertex[1].set(rect.fRight, rect.fTop);
1169 vertex[2].set(rect.fRight, rect.fBottom);
1170 vertex[3].set(rect.fLeft, rect.fBottom);
1171 vertex[4].set(rect.fLeft, rect.fTop);
1172 }
1173
1174 GrDrawTarget::AutoViewMatrixRestore avmr;
1175 if (NULL != matrix) {
1176 avmr.set(target);
1177 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001178 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001179 }
1180
1181 target->drawNonIndexed(primType, 0, vertCount);
1182 } else {
1183 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001184 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1185
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001186 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001187 fGpu->getUnitSquareVertexBuffer());
1188 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1189 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001190 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001191 0, rect.height(), rect.fTop,
1192 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001193
1194 if (NULL != matrix) {
1195 m.postConcat(*matrix);
1196 }
1197
1198 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001199 target->preConcatSamplerMatrices(stageMask, m);
1200
bsalomon@google.com27847de2011-02-22 20:59:41 +00001201 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1202 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001203 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001204 #endif
1205 }
1206}
1207
1208void GrContext::drawRectToRect(const GrPaint& paint,
1209 const GrRect& dstRect,
1210 const GrRect& srcRect,
1211 const GrMatrix* dstMatrix,
1212 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001213 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001214
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001215 // srcRect refers to paint's first texture
1216 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001217 drawRect(paint, dstRect, -1, dstMatrix);
1218 return;
1219 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001220
bsalomon@google.com27847de2011-02-22 20:59:41 +00001221 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1222
1223#if GR_STATIC_RECT_VB
1224 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001225
1226 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1228
1229 GrMatrix m;
1230
1231 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1232 0, dstRect.height(), dstRect.fTop,
1233 0, 0, GrMatrix::I()[8]);
1234 if (NULL != dstMatrix) {
1235 m.postConcat(*dstMatrix);
1236 }
1237 target->preConcatViewMatrix(m);
1238
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001239 // srcRect refers to first stage
1240 int otherStageMask = paint.getActiveStageMask() &
1241 (~(1 << GrPaint::kFirstTextureStage));
1242 if (otherStageMask) {
1243 target->preConcatSamplerMatrices(otherStageMask, m);
1244 }
1245
bsalomon@google.com27847de2011-02-22 20:59:41 +00001246 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1247 0, srcRect.height(), srcRect.fTop,
1248 0, 0, GrMatrix::I()[8]);
1249 if (NULL != srcMatrix) {
1250 m.postConcat(*srcMatrix);
1251 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001252 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001253
1254 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1255 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1256#else
1257
1258 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001259#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001260 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001261#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001262 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1263#endif
1264
1265 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1266 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1267 srcRects[0] = &srcRect;
1268 srcMatrices[0] = srcMatrix;
1269
1270 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1271#endif
1272}
1273
1274void GrContext::drawVertices(const GrPaint& paint,
1275 GrPrimitiveType primitiveType,
1276 int vertexCount,
1277 const GrPoint positions[],
1278 const GrPoint texCoords[],
1279 const GrColor colors[],
1280 const uint16_t indices[],
1281 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001282 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001283
1284 GrDrawTarget::AutoReleaseGeometry geo;
1285
1286 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1287
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001288 bool hasTexCoords[GrPaint::kTotalStages] = {
1289 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1290 0 // remaining stages use positions
1291 };
1292
1293 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001294
1295 if (NULL != colors) {
1296 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001297 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001298 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001299
1300 if (sizeof(GrPoint) != vertexSize) {
1301 if (!geo.set(target, layout, vertexCount, 0)) {
1302 GrPrintf("Failed to get space for vertices!");
1303 return;
1304 }
1305 int texOffsets[GrDrawTarget::kMaxTexCoords];
1306 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001307 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1308 texOffsets,
1309 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001310 void* curVertex = geo.vertices();
1311
1312 for (int i = 0; i < vertexCount; ++i) {
1313 *((GrPoint*)curVertex) = positions[i];
1314
1315 if (texOffsets[0] > 0) {
1316 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1317 }
1318 if (colorOffset > 0) {
1319 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1320 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001321 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001322 }
1323 } else {
1324 target->setVertexSourceToArray(layout, positions, vertexCount);
1325 }
1326
bsalomon@google.com91958362011-06-13 17:58:13 +00001327 // we don't currently apply offscreen AA to this path. Need improved
1328 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001329
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001330 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001331 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001332 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001333 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001334 target->drawNonIndexed(primitiveType, 0, vertexCount);
1335 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001336}
1337
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001338///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001339
reed@google.com07f3ee12011-05-16 17:21:57 +00001340void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1341 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001342
bsalomon@google.com27847de2011-02-22 20:59:41 +00001343 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comee435122011-07-01 14:57:55 +00001344 GrPathRenderer* pr = this->getPathRenderer(path, fill);
1345 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1346 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001347
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001348 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001349 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001350
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001351 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001352
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001353 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001354 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1355 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001356 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001357 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001358 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001359 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001360 return;
1361 }
1362 }
reed@google.com70c136e2011-06-03 19:51:26 +00001363
reed@google.com07f3ee12011-05-16 17:21:57 +00001364 GrRect pathBounds = path.getBounds();
1365 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001366 if (NULL != translate) {
1367 pathBounds.offset(*translate);
1368 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001369 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001370 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001371 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001372 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001373 return;
1374 }
1375 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001376 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001377 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1378 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001379 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1380 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1381 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001382 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001383 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1384 }
1385 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001386 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001387 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001388 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1389 GrRect rect;
1390 if (clipIBounds.fTop < bound.fTop) {
1391 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1392 clipIBounds.fRight, bound.fTop);
1393 target->drawSimpleRect(rect, NULL, stageMask);
1394 }
1395 if (clipIBounds.fLeft < bound.fLeft) {
1396 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1397 bound.fLeft, bound.fBottom);
1398 target->drawSimpleRect(rect, NULL, stageMask);
1399 }
1400 if (clipIBounds.fRight > bound.fRight) {
1401 rect.setLTRB(bound.fRight, bound.fTop,
1402 clipIBounds.fRight, bound.fBottom);
1403 target->drawSimpleRect(rect, NULL, stageMask);
1404 }
1405 if (clipIBounds.fBottom > bound.fBottom) {
1406 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1407 clipIBounds.fRight, clipIBounds.fBottom);
1408 target->drawSimpleRect(rect, NULL, stageMask);
1409 }
1410 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001411 return;
1412 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001413 }
1414 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001416
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417////////////////////////////////////////////////////////////////////////////////
1418
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001419void GrContext::flush(int flagsBitfield) {
1420 if (kDiscard_FlushBit & flagsBitfield) {
1421 fDrawBuffer->reset();
1422 } else {
1423 flushDrawBuffer();
1424 }
1425
1426 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001427 fGpu->forceRenderTargetFlush();
1428 }
1429}
1430
1431void GrContext::flushText() {
1432 if (kText_DrawCategory == fLastDrawCategory) {
1433 flushDrawBuffer();
1434 }
1435}
1436
1437void GrContext::flushDrawBuffer() {
1438#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001439 if (fDrawBuffer) {
1440 fDrawBuffer->playback(fGpu);
1441 fDrawBuffer->reset();
1442 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001443#endif
1444}
1445
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001446bool GrContext::readTexturePixels(GrTexture* texture,
1447 int left, int top, int width, int height,
1448 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001449 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001450
1451 // TODO: code read pixels for textures that aren't rendertargets
1452
1453 this->flush();
1454 GrRenderTarget* target = texture->asRenderTarget();
1455 if (NULL != target) {
1456 return fGpu->readPixels(target,
1457 left, top, width, height,
1458 config, buffer);
1459 } else {
1460 return false;
1461 }
1462}
1463
1464bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1465 int left, int top, int width, int height,
1466 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001467 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001468 uint32_t flushFlags = 0;
1469 if (NULL == target) {
1470 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1471 }
1472
1473 this->flush(flushFlags);
1474 return fGpu->readPixels(target,
1475 left, top, width, height,
1476 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001477}
1478
1479void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001480 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001481 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001482 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001483
1484 // TODO: when underlying api has a direct way to do this we should use it
1485 // (e.g. glDrawPixels on desktop GL).
1486
bsalomon@google.com5c638652011-07-18 19:31:59 +00001487 this->flush(true);
1488
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001489 const GrTextureDesc desc = {
1490 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001491 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001492 GrAutoScratchTexture ast(this, desc);
1493 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494 if (NULL == texture) {
1495 return;
1496 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001497 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498
bsalomon@google.com27847de2011-02-22 20:59:41 +00001499 GrDrawTarget::AutoStateRestore asr(fGpu);
1500
1501 GrMatrix matrix;
1502 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1503 fGpu->setViewMatrix(matrix);
1504
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001505 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001506 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1507 fGpu->setAlpha(0xFF);
1508 fGpu->setBlendFunc(kOne_BlendCoeff,
1509 kZero_BlendCoeff);
1510 fGpu->setTexture(0, texture);
1511
1512 GrSamplerState sampler;
1513 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001514 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001515 sampler.setMatrix(matrix);
1516 fGpu->setSamplerState(0, sampler);
1517
1518 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1519 static const int VCOUNT = 4;
1520
1521 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1522 if (!geo.succeeded()) {
1523 return;
1524 }
1525 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1526 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1527}
1528////////////////////////////////////////////////////////////////////////////////
1529
1530void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001531
1532 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1533 int s = i + GrPaint::kFirstTextureStage;
1534 target->setTexture(s, paint.getTexture(i));
1535 target->setSamplerState(s, *paint.getTextureSampler(i));
1536 }
1537
1538 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1539
1540 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1541 int s = i + GrPaint::kFirstMaskStage;
1542 target->setTexture(s, paint.getMask(i));
1543 target->setSamplerState(s, *paint.getMaskSampler(i));
1544 }
1545
bsalomon@google.com27847de2011-02-22 20:59:41 +00001546 target->setColor(paint.fColor);
1547
1548 if (paint.fDither) {
1549 target->enableState(GrDrawTarget::kDither_StateBit);
1550 } else {
1551 target->disableState(GrDrawTarget::kDither_StateBit);
1552 }
1553 if (paint.fAntiAlias) {
1554 target->enableState(GrDrawTarget::kAntialias_StateBit);
1555 } else {
1556 target->disableState(GrDrawTarget::kAntialias_StateBit);
1557 }
1558 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001559 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001560}
1561
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001562GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001563 DrawCategory category) {
1564 if (category != fLastDrawCategory) {
1565 flushDrawBuffer();
1566 fLastDrawCategory = category;
1567 }
1568 SetPaint(paint, fGpu);
1569 GrDrawTarget* target = fGpu;
1570 switch (category) {
1571 case kText_DrawCategory:
1572#if DEFER_TEXT_RENDERING
1573 target = fDrawBuffer;
1574 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1575#else
1576 target = fGpu;
1577#endif
1578 break;
1579 case kUnbuffered_DrawCategory:
1580 target = fGpu;
1581 break;
1582 case kBuffered_DrawCategory:
1583 target = fDrawBuffer;
1584 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1585 break;
1586 }
1587 return target;
1588}
1589
1590////////////////////////////////////////////////////////////////////////////////
1591
bsalomon@google.com27847de2011-02-22 20:59:41 +00001592void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001593 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001594 fGpu->setRenderTarget(target);
1595}
1596
1597GrRenderTarget* GrContext::getRenderTarget() {
1598 return fGpu->getRenderTarget();
1599}
1600
1601const GrRenderTarget* GrContext::getRenderTarget() const {
1602 return fGpu->getRenderTarget();
1603}
1604
1605const GrMatrix& GrContext::getMatrix() const {
1606 return fGpu->getViewMatrix();
1607}
1608
1609void GrContext::setMatrix(const GrMatrix& m) {
1610 fGpu->setViewMatrix(m);
1611}
1612
1613void GrContext::concatMatrix(const GrMatrix& m) const {
1614 fGpu->preConcatViewMatrix(m);
1615}
1616
1617static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1618 intptr_t mask = 1 << shift;
1619 if (pred) {
1620 bits |= mask;
1621 } else {
1622 bits &= ~mask;
1623 }
1624 return bits;
1625}
1626
1627void GrContext::resetStats() {
1628 fGpu->resetStats();
1629}
1630
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001631const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001632 return fGpu->getStats();
1633}
1634
1635void GrContext::printStats() const {
1636 fGpu->printStats();
1637}
1638
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001639GrContext::GrContext(GrGpu* gpu) :
1640 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1641 gpu->supportsStencilWrapOps()) {
1642
bsalomon@google.com27847de2011-02-22 20:59:41 +00001643 fGpu = gpu;
1644 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001645 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001646
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001647 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1648 fGpu->setClipPathRenderer(fCustomPathRenderer);
1649
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001650 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1651 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001652 fFontCache = new GrFontCache(fGpu);
1653
1654 fLastDrawCategory = kUnbuffered_DrawCategory;
1655
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001656 fDrawBuffer = NULL;
1657 fDrawBufferVBAllocPool = NULL;
1658 fDrawBufferIBAllocPool = NULL;
1659
bsalomon@google.com205d4602011-04-25 12:43:45 +00001660 fAAFillRectIndexBuffer = NULL;
1661 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001662
1663 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1664 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1665 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1666 }
1667 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001668
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001669 this->setupDrawBuffer();
1670}
1671
1672void GrContext::setupDrawBuffer() {
1673
1674 GrAssert(NULL == fDrawBuffer);
1675 GrAssert(NULL == fDrawBufferVBAllocPool);
1676 GrAssert(NULL == fDrawBufferIBAllocPool);
1677
bsalomon@google.com27847de2011-02-22 20:59:41 +00001678#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001679 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001680 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001681 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1682 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001683 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001684 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001685 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001686 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1687
1688 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1689 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001690#endif
1691
1692#if BATCH_RECT_TO_RECT
1693 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1694#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001695}
1696
bsalomon@google.com27847de2011-02-22 20:59:41 +00001697GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1698 GrDrawTarget* target;
1699#if DEFER_TEXT_RENDERING
1700 target = prepareToDraw(paint, kText_DrawCategory);
1701#else
1702 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1703#endif
1704 SetPaint(paint, target);
1705 return target;
1706}
1707
1708const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1709 return fGpu->getQuadIndexBuffer();
1710}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001711
bsalomon@google.comee435122011-07-01 14:57:55 +00001712GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001713 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001714 if (NULL != fCustomPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +00001715 fCustomPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001716 return fCustomPathRenderer;
1717 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +00001718 GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001719 return &fDefaultPathRenderer;
1720 }
1721}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001722
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001723void GrContext::convolveInX(GrTexture* texture,
1724 const SkRect& rect,
1725 const float* kernel,
1726 int kernelWidth) {
1727 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1728 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1729}
1730
1731void GrContext::convolveInY(GrTexture* texture,
1732 const SkRect& rect,
1733 const float* kernel,
1734 int kernelWidth) {
1735 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1736 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1737}
1738
1739void GrContext::convolve(GrTexture* texture,
1740 const SkRect& rect,
1741 float imageIncrement[2],
1742 const float* kernel,
1743 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001744 GrDrawTarget::AutoStateRestore asr(fGpu);
1745 GrMatrix sampleM;
1746 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1747 GrSamplerState::kClamp_WrapMode,
1748 GrSamplerState::kConvolution_Filter);
1749 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001750 sampleM.setScale(GR_Scalar1 / texture->width(),
1751 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001752 sampler.setMatrix(sampleM);
1753 fGpu->setSamplerState(0, sampler);
1754 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001755 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001756 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001757 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1758}