blob: 834b3845bc472ec550596836da950bec31feedf3 [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 }
468 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
469 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
470 return NULL;
471 }
472 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
473 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
474 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
475 return NULL;
476 }
477 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000478}
479
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000480GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000481 return fGpu->createRenderTargetFrom3DApiState();
482}
483
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000484///////////////////////////////////////////////////////////////////////////////
485
bsalomon@google.com27847de2011-02-22 20:59:41 +0000486bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
487 int width, int height) {
488 if (!fGpu->supports8BitPalette()) {
489 return false;
490 }
491
492
493 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
494
495 if (!isPow2) {
496 if (!fGpu->npotTextureSupport()) {
497 return false;
498 }
499
500 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
501 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
502 if (tiled && !fGpu->npotTextureTileSupport()) {
503 return false;
504 }
505 }
506 return true;
507}
508
509////////////////////////////////////////////////////////////////////////////////
510
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000511const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
512
bsalomon@google.com27847de2011-02-22 20:59:41 +0000513void GrContext::setClip(const GrClip& clip) {
514 fGpu->setClip(clip);
515 fGpu->enableState(GrDrawTarget::kClip_StateBit);
516}
517
518void GrContext::setClip(const GrIRect& rect) {
519 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000520 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000521 fGpu->setClip(clip);
522}
523
524////////////////////////////////////////////////////////////////////////////////
525
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000526void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000527 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000528 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000529}
530
531void GrContext::drawPaint(const GrPaint& paint) {
532 // set rect to be big enough to fill the space, but not super-huge, so we
533 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000534 GrRect r;
535 r.setLTRB(0, 0,
536 GrIntToScalar(getRenderTarget()->width()),
537 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000538 GrMatrix inverse;
539 if (fGpu->getViewInverse(&inverse)) {
540 inverse.mapRect(&r);
541 } else {
542 GrPrintf("---- fGpu->getViewInverse failed\n");
543 }
544 this->drawRect(paint, r);
545}
546
bsalomon@google.com205d4602011-04-25 12:43:45 +0000547////////////////////////////////////////////////////////////////////////////////
548
bsalomon@google.com91958362011-06-13 17:58:13 +0000549struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000550 enum Downsample {
551 k4x4TwoPass_Downsample,
552 k4x4SinglePass_Downsample,
553 kFSAA_Downsample
554 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000555 int fTileSizeX;
556 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000557 int fTileCountX;
558 int fTileCountY;
559 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000560 GrAutoScratchTexture fOffscreen0;
561 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000562 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000563 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000564};
565
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000566bool GrContext::doOffscreenAA(GrDrawTarget* target,
567 const GrPaint& paint,
568 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000569#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000570 return false;
571#else
572 if (!paint.fAntiAlias) {
573 return false;
574 }
575 if (isLines && fGpu->supportsAALines()) {
576 return false;
577 }
578 if (target->getRenderTarget()->isMultisampled()) {
579 return false;
580 }
581 // we have to be sure that the blend equation is expressible
582 // as simple src / dst coeffecients when the source
583 // is already modulated by the coverage fraction.
584 // We could use dual-source blending to get the correct per-pixel
585 // dst coeffecient for the remaining cases.
586 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
587 kOne_BlendCoeff != paint.fDstBlendCoeff &&
588 kISA_BlendCoeff != paint.fDstBlendCoeff) {
589 return false;
590 }
591 return true;
592#endif
593}
594
bsalomon@google.com91958362011-06-13 17:58:13 +0000595bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000596 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000597 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000598 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000599 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000600
601 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000602
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000603 GrAssert(NULL == record->fOffscreen0.texture());
604 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000605 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000606
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000607 int boundW = boundRect.width();
608 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000609
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000610 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000611
612 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
613 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
614
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000615 if (requireStencil) {
616 desc.fFlags = kRenderTarget_GrTextureFlagBit;
617 } else {
618 desc.fFlags = kRenderTarget_GrTextureFlagBit |
619 kNoStencil_GrTextureFlagBit;
620 }
621
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000622 desc.fFormat = kRGBA_8888_GrPixelConfig;
623
bsalomon@google.com91958362011-06-13 17:58:13 +0000624 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000625 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000626 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000627 desc.fAALevel = kMed_GrAALevel;
628 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000629 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
630 OffscreenRecord::k4x4SinglePass_Downsample :
631 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000632 record->fScale = OFFSCREEN_SSAA_SCALE;
633 // both downsample paths assume this
634 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000635 desc.fAALevel = kNone_GrAALevel;
636 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000637 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
638 // of simple circles?
639 if (pr) {
640 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
641 }
642
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000643 desc.fWidth *= record->fScale;
644 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000645 record->fOffscreen0.set(this, desc);
646 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000647 return false;
648 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000649 // the approximate lookup might have given us some slop space, might as well
650 // use it when computing the tiles size.
651 // these are scale values, will adjust after considering
652 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000653 record->fTileSizeX = record->fOffscreen0.texture()->width();
654 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000655
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000656 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000657 desc.fWidth /= 2;
658 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000659 record->fOffscreen1.set(this, desc);
660 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000661 return false;
662 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000663 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000664 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000665 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000666 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000667 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000668 record->fTileSizeX /= record->fScale;
669 record->fTileSizeY /= record->fScale;
670
671 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
672 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
673
tomhudson@google.com237a4612011-07-19 15:44:00 +0000674 record->fClip = target->getClip();
675
bsalomon@google.com91958362011-06-13 17:58:13 +0000676 target->saveCurrentDrawState(&record->fSavedState);
677 return true;
678}
679
680void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
681 const GrIRect& boundRect,
682 int tileX, int tileY,
683 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000684
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000685 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000686 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000687
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000688 GrPaint tempPaint;
689 tempPaint.reset();
690 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000691 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000692
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000693 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000694 int left = boundRect.fLeft + tileX * record->fTileSizeX;
695 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000696 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000697 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000698 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000699 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000700 target->postConcatViewMatrix(scaleM);
701
bsalomon@google.com91958362011-06-13 17:58:13 +0000702 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000703 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000704 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000705 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000706 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
707 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000708 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000709#if 0
710 // visualize tile boundaries by setting edges of offscreen to white
711 // and interior to tranparent. black.
712 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000713
bsalomon@google.com91958362011-06-13 17:58:13 +0000714 static const int gOffset = 2;
715 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
716 record->fScale * w - gOffset,
717 record->fScale * h - gOffset);
718 target->clear(&clear2, 0x0);
719#else
720 target->clear(&clear, 0x0);
721#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000722}
723
bsalomon@google.com91958362011-06-13 17:58:13 +0000724void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000725 const GrPaint& paint,
726 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000727 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000728 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000729 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000730 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000731 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000732 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000733 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
734 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000735 tileRect.fRight = (tileX == record->fTileCountX-1) ?
736 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000737 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000738 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
739 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000740 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000741
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000742 GrSamplerState::Filter filter;
743 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
744 filter = GrSamplerState::k4x4Downsample_Filter;
745 } else {
746 filter = GrSamplerState::kBilinear_Filter;
747 }
748
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000749 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000750 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000751 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000752
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000753 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000754 int scale;
755
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000756 enum {
757 kOffscreenStage = GrPaint::kTotalStages,
758 };
759
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000760 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000761 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000762 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000763 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000764
765 // Do 2x2 downsample from first to second
766 target->setTexture(kOffscreenStage, src);
767 target->setRenderTarget(dst);
768 target->setViewMatrix(GrMatrix::I());
769 sampleM.setScale(scale * GR_Scalar1 / src->width(),
770 scale * GR_Scalar1 / src->height());
771 sampler.setMatrix(sampleM);
772 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000773 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
774 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000775 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
776
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000777 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000778 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000779 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000780 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000781 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000782 } else {
783 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
784 record->fDownsample);
785 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000786 }
787
bsalomon@google.com91958362011-06-13 17:58:13 +0000788 // setup for draw back to main RT, we use the original
789 // draw state setup by the caller plus an additional coverage
790 // stage to handle the AA resolve. Also, we use an identity
791 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000792 int stageMask = paint.getActiveStageMask();
793
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000794 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000795 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000796
797 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000798 GrMatrix invVM;
799 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000800 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000801 }
802 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000803 // This is important when tiling, otherwise second tile's
804 // pass 1 view matrix will be incorrect.
805 GrDrawTarget::AutoViewMatrixRestore avmr(target);
806
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000807 target->setViewMatrix(GrMatrix::I());
808
809 target->setTexture(kOffscreenStage, src);
810 sampleM.setScale(scale * GR_Scalar1 / src->width(),
811 scale * GR_Scalar1 / src->height());
812 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000813 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000814 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000815 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000816
reed@google.com20efde72011-05-09 17:00:02 +0000817 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000818 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000819 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000820 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000821}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000822
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000823void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
824 GrPathRenderer* pr,
825 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000826 if (pr) {
827 // Counterpart of scale() in prepareForOffscreenAA()
828 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
829 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000830 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000831}
832
833////////////////////////////////////////////////////////////////////////////////
834
bsalomon@google.com27847de2011-02-22 20:59:41 +0000835/* create a triangle strip that strokes the specified triangle. There are 8
836 unique vertices, but we repreat the last 2 to close up. Alternatively we
837 could use an indices array, and then only send 8 verts, but not sure that
838 would be faster.
839 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000840static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000841 GrScalar width) {
842 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000843 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000844
845 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
846 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
847 verts[2].set(rect.fRight - rad, rect.fTop + rad);
848 verts[3].set(rect.fRight + rad, rect.fTop - rad);
849 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
850 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
851 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
852 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
853 verts[8] = verts[0];
854 verts[9] = verts[1];
855}
856
bsalomon@google.com205d4602011-04-25 12:43:45 +0000857static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000858 // FIXME: This was copied from SkGpuDevice, seems like
859 // we should have already smeared a in caller if that
860 // is what is desired.
861 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000862 unsigned a = GrColorUnpackA(paint.fColor);
863 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000864 } else {
865 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000866 }
867}
868
869static void setInsetFan(GrPoint* pts, size_t stride,
870 const GrRect& r, GrScalar dx, GrScalar dy) {
871 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
872}
873
874static const uint16_t gFillAARectIdx[] = {
875 0, 1, 5, 5, 4, 0,
876 1, 2, 6, 6, 5, 1,
877 2, 3, 7, 7, 6, 2,
878 3, 0, 4, 4, 7, 3,
879 4, 5, 6, 6, 7, 4,
880};
881
882int GrContext::aaFillRectIndexCount() const {
883 return GR_ARRAY_COUNT(gFillAARectIdx);
884}
885
886GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
887 if (NULL == fAAFillRectIndexBuffer) {
888 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
889 false);
890 GrAssert(NULL != fAAFillRectIndexBuffer);
891#if GR_DEBUG
892 bool updated =
893#endif
894 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
895 sizeof(gFillAARectIdx));
896 GR_DEBUGASSERT(updated);
897 }
898 return fAAFillRectIndexBuffer;
899}
900
901static const uint16_t gStrokeAARectIdx[] = {
902 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
903 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
904 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
905 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
906
907 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
908 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
909 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
910 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
911
912 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
913 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
914 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
915 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
916};
917
918int GrContext::aaStrokeRectIndexCount() const {
919 return GR_ARRAY_COUNT(gStrokeAARectIdx);
920}
921
922GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
923 if (NULL == fAAStrokeRectIndexBuffer) {
924 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
925 false);
926 GrAssert(NULL != fAAStrokeRectIndexBuffer);
927#if GR_DEBUG
928 bool updated =
929#endif
930 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
931 sizeof(gStrokeAARectIdx));
932 GR_DEBUGASSERT(updated);
933 }
934 return fAAStrokeRectIndexBuffer;
935}
936
937void GrContext::fillAARect(GrDrawTarget* target,
938 const GrPaint& paint,
939 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000940 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
941 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000942
943 size_t vsize = GrDrawTarget::VertexSize(layout);
944
945 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
946
947 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
948
949 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
950 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
951
952 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
953 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
954
955 verts += sizeof(GrPoint);
956 for (int i = 0; i < 4; ++i) {
957 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
958 }
959
960 GrColor innerColor = getColorForMesh(paint);
961 verts += 4 * vsize;
962 for (int i = 0; i < 4; ++i) {
963 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
964 }
965
966 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
967
968 target->drawIndexed(kTriangles_PrimitiveType, 0,
969 0, 8, this->aaFillRectIndexCount());
970}
971
972void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
973 const GrRect& devRect, const GrVec& devStrokeSize) {
974 const GrScalar& dx = devStrokeSize.fX;
975 const GrScalar& dy = devStrokeSize.fY;
976 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
977 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
978
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000979 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
980 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000981
982 GrScalar spare;
983 {
984 GrScalar w = devRect.width() - dx;
985 GrScalar h = devRect.height() - dy;
986 spare = GrMin(w, h);
987 }
988
989 if (spare <= 0) {
990 GrRect r(devRect);
991 r.inset(-rx, -ry);
992 fillAARect(target, paint, r);
993 return;
994 }
995
996 size_t vsize = GrDrawTarget::VertexSize(layout);
997
998 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
999
1000 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1001
1002 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1003 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1004 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1005 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1006
1007 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1008 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1009 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1010 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1011
1012 verts += sizeof(GrPoint);
1013 for (int i = 0; i < 4; ++i) {
1014 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1015 }
1016
1017 GrColor innerColor = getColorForMesh(paint);
1018 verts += 4 * vsize;
1019 for (int i = 0; i < 8; ++i) {
1020 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1021 }
1022
1023 verts += 8 * vsize;
1024 for (int i = 0; i < 8; ++i) {
1025 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1026 }
1027
1028 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1029 target->drawIndexed(kTriangles_PrimitiveType,
1030 0, 0, 16, aaStrokeRectIndexCount());
1031}
1032
reed@google.com20efde72011-05-09 17:00:02 +00001033/**
1034 * Returns true if the rects edges are integer-aligned.
1035 */
1036static bool isIRect(const GrRect& r) {
1037 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1038 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1039}
1040
bsalomon@google.com205d4602011-04-25 12:43:45 +00001041static bool apply_aa_to_rect(GrDrawTarget* target,
1042 GrGpu* gpu,
1043 const GrPaint& paint,
1044 const GrRect& rect,
1045 GrScalar width,
1046 const GrMatrix* matrix,
1047 GrMatrix* combinedMatrix,
1048 GrRect* devRect) {
1049 // we use a simple alpha ramp to do aa on axis-aligned rects
1050 // do AA with alpha ramp if the caller requested AA, the rect
1051 // will be axis-aligned,the render target is not
1052 // multisampled, and the rect won't land on integer coords.
1053
1054 if (!paint.fAntiAlias) {
1055 return false;
1056 }
1057
1058 if (target->getRenderTarget()->isMultisampled()) {
1059 return false;
1060 }
1061
1062 if (0 == width && gpu->supportsAALines()) {
1063 return false;
1064 }
1065
1066 if (!target->getViewMatrix().preservesAxisAlignment()) {
1067 return false;
1068 }
1069
1070 if (NULL != matrix &&
1071 !matrix->preservesAxisAlignment()) {
1072 return false;
1073 }
1074
1075 *combinedMatrix = target->getViewMatrix();
1076 if (NULL != matrix) {
1077 combinedMatrix->preConcat(*matrix);
1078 GrAssert(combinedMatrix->preservesAxisAlignment());
1079 }
1080
1081 combinedMatrix->mapRect(devRect, rect);
1082 devRect->sort();
1083
1084 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001085 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001086 } else {
1087 return true;
1088 }
1089}
1090
bsalomon@google.com27847de2011-02-22 20:59:41 +00001091void GrContext::drawRect(const GrPaint& paint,
1092 const GrRect& rect,
1093 GrScalar width,
1094 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001095 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001096
1097 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001098 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001099
bsalomon@google.com205d4602011-04-25 12:43:45 +00001100 GrRect devRect = rect;
1101 GrMatrix combinedMatrix;
1102 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1103 &combinedMatrix, &devRect);
1104
1105 if (doAA) {
1106 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001107 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001108 GrMatrix inv;
1109 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001110 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001111 }
1112 }
1113 target->setViewMatrix(GrMatrix::I());
1114 if (width >= 0) {
1115 GrVec strokeSize;;
1116 if (width > 0) {
1117 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001118 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001119 strokeSize.setAbs(strokeSize);
1120 } else {
1121 strokeSize.set(GR_Scalar1, GR_Scalar1);
1122 }
1123 strokeAARect(target, paint, devRect, strokeSize);
1124 } else {
1125 fillAARect(target, paint, devRect);
1126 }
1127 return;
1128 }
1129
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130 if (width >= 0) {
1131 // TODO: consider making static vertex buffers for these cases.
1132 // Hairline could be done by just adding closing vertex to
1133 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001134 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1135
bsalomon@google.com27847de2011-02-22 20:59:41 +00001136 static const int worstCaseVertCount = 10;
1137 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1138
1139 if (!geo.succeeded()) {
1140 return;
1141 }
1142
1143 GrPrimitiveType primType;
1144 int vertCount;
1145 GrPoint* vertex = geo.positions();
1146
1147 if (width > 0) {
1148 vertCount = 10;
1149 primType = kTriangleStrip_PrimitiveType;
1150 setStrokeRectStrip(vertex, rect, width);
1151 } else {
1152 // hairline
1153 vertCount = 5;
1154 primType = kLineStrip_PrimitiveType;
1155 vertex[0].set(rect.fLeft, rect.fTop);
1156 vertex[1].set(rect.fRight, rect.fTop);
1157 vertex[2].set(rect.fRight, rect.fBottom);
1158 vertex[3].set(rect.fLeft, rect.fBottom);
1159 vertex[4].set(rect.fLeft, rect.fTop);
1160 }
1161
1162 GrDrawTarget::AutoViewMatrixRestore avmr;
1163 if (NULL != matrix) {
1164 avmr.set(target);
1165 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001166 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001167 }
1168
1169 target->drawNonIndexed(primType, 0, vertCount);
1170 } else {
1171 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001172 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1173
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001174 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001175 fGpu->getUnitSquareVertexBuffer());
1176 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1177 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001178 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001179 0, rect.height(), rect.fTop,
1180 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001181
1182 if (NULL != matrix) {
1183 m.postConcat(*matrix);
1184 }
1185
1186 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001187 target->preConcatSamplerMatrices(stageMask, m);
1188
bsalomon@google.com27847de2011-02-22 20:59:41 +00001189 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1190 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001191 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001192 #endif
1193 }
1194}
1195
1196void GrContext::drawRectToRect(const GrPaint& paint,
1197 const GrRect& dstRect,
1198 const GrRect& srcRect,
1199 const GrMatrix* dstMatrix,
1200 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001201 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001202
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001203 // srcRect refers to paint's first texture
1204 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001205 drawRect(paint, dstRect, -1, dstMatrix);
1206 return;
1207 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001208
bsalomon@google.com27847de2011-02-22 20:59:41 +00001209 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1210
1211#if GR_STATIC_RECT_VB
1212 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001213
1214 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001215 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1216
1217 GrMatrix m;
1218
1219 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1220 0, dstRect.height(), dstRect.fTop,
1221 0, 0, GrMatrix::I()[8]);
1222 if (NULL != dstMatrix) {
1223 m.postConcat(*dstMatrix);
1224 }
1225 target->preConcatViewMatrix(m);
1226
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001227 // srcRect refers to first stage
1228 int otherStageMask = paint.getActiveStageMask() &
1229 (~(1 << GrPaint::kFirstTextureStage));
1230 if (otherStageMask) {
1231 target->preConcatSamplerMatrices(otherStageMask, m);
1232 }
1233
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1235 0, srcRect.height(), srcRect.fTop,
1236 0, 0, GrMatrix::I()[8]);
1237 if (NULL != srcMatrix) {
1238 m.postConcat(*srcMatrix);
1239 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001240 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001241
1242 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1243 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1244#else
1245
1246 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001247#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001248 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001249#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001250 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1251#endif
1252
1253 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1254 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1255 srcRects[0] = &srcRect;
1256 srcMatrices[0] = srcMatrix;
1257
1258 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1259#endif
1260}
1261
1262void GrContext::drawVertices(const GrPaint& paint,
1263 GrPrimitiveType primitiveType,
1264 int vertexCount,
1265 const GrPoint positions[],
1266 const GrPoint texCoords[],
1267 const GrColor colors[],
1268 const uint16_t indices[],
1269 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001270 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001271
1272 GrDrawTarget::AutoReleaseGeometry geo;
1273
1274 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1275
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001276 bool hasTexCoords[GrPaint::kTotalStages] = {
1277 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1278 0 // remaining stages use positions
1279 };
1280
1281 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001282
1283 if (NULL != colors) {
1284 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001285 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001286 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287
1288 if (sizeof(GrPoint) != vertexSize) {
1289 if (!geo.set(target, layout, vertexCount, 0)) {
1290 GrPrintf("Failed to get space for vertices!");
1291 return;
1292 }
1293 int texOffsets[GrDrawTarget::kMaxTexCoords];
1294 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001295 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1296 texOffsets,
1297 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298 void* curVertex = geo.vertices();
1299
1300 for (int i = 0; i < vertexCount; ++i) {
1301 *((GrPoint*)curVertex) = positions[i];
1302
1303 if (texOffsets[0] > 0) {
1304 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1305 }
1306 if (colorOffset > 0) {
1307 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1308 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001309 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001310 }
1311 } else {
1312 target->setVertexSourceToArray(layout, positions, vertexCount);
1313 }
1314
bsalomon@google.com91958362011-06-13 17:58:13 +00001315 // we don't currently apply offscreen AA to this path. Need improved
1316 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001317
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001318 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001319 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001320 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001321 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001322 target->drawNonIndexed(primitiveType, 0, vertexCount);
1323 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324}
1325
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001326///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327
reed@google.com07f3ee12011-05-16 17:21:57 +00001328void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1329 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001330
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comee435122011-07-01 14:57:55 +00001332 GrPathRenderer* pr = this->getPathRenderer(path, fill);
1333 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1334 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001335
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001336 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001337 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001338
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001339 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001340
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001341 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001342 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1343 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001344 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001345 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001346 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001347 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001348 return;
1349 }
1350 }
reed@google.com70c136e2011-06-03 19:51:26 +00001351
reed@google.com07f3ee12011-05-16 17:21:57 +00001352 GrRect pathBounds = path.getBounds();
1353 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001354 if (NULL != translate) {
1355 pathBounds.offset(*translate);
1356 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001357 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001358 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001359 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001360 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001361 return;
1362 }
1363 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001364 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001365 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1366 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001367 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1368 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1369 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001370 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001371 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1372 }
1373 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001374 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001375 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001376 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1377 GrRect rect;
1378 if (clipIBounds.fTop < bound.fTop) {
1379 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1380 clipIBounds.fRight, bound.fTop);
1381 target->drawSimpleRect(rect, NULL, stageMask);
1382 }
1383 if (clipIBounds.fLeft < bound.fLeft) {
1384 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1385 bound.fLeft, bound.fBottom);
1386 target->drawSimpleRect(rect, NULL, stageMask);
1387 }
1388 if (clipIBounds.fRight > bound.fRight) {
1389 rect.setLTRB(bound.fRight, bound.fTop,
1390 clipIBounds.fRight, bound.fBottom);
1391 target->drawSimpleRect(rect, NULL, stageMask);
1392 }
1393 if (clipIBounds.fBottom > bound.fBottom) {
1394 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1395 clipIBounds.fRight, clipIBounds.fBottom);
1396 target->drawSimpleRect(rect, NULL, stageMask);
1397 }
1398 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001399 return;
1400 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001401 }
1402 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001403}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001404
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405////////////////////////////////////////////////////////////////////////////////
1406
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001407void GrContext::flush(int flagsBitfield) {
1408 if (kDiscard_FlushBit & flagsBitfield) {
1409 fDrawBuffer->reset();
1410 } else {
1411 flushDrawBuffer();
1412 }
1413
1414 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 fGpu->forceRenderTargetFlush();
1416 }
1417}
1418
1419void GrContext::flushText() {
1420 if (kText_DrawCategory == fLastDrawCategory) {
1421 flushDrawBuffer();
1422 }
1423}
1424
1425void GrContext::flushDrawBuffer() {
1426#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001427 if (fDrawBuffer) {
1428 fDrawBuffer->playback(fGpu);
1429 fDrawBuffer->reset();
1430 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001431#endif
1432}
1433
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001434bool GrContext::readTexturePixels(GrTexture* texture,
1435 int left, int top, int width, int height,
1436 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001437 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001438
1439 // TODO: code read pixels for textures that aren't rendertargets
1440
1441 this->flush();
1442 GrRenderTarget* target = texture->asRenderTarget();
1443 if (NULL != target) {
1444 return fGpu->readPixels(target,
1445 left, top, width, height,
1446 config, buffer);
1447 } else {
1448 return false;
1449 }
1450}
1451
1452bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1453 int left, int top, int width, int height,
1454 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001455 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001456 uint32_t flushFlags = 0;
1457 if (NULL == target) {
1458 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1459 }
1460
1461 this->flush(flushFlags);
1462 return fGpu->readPixels(target,
1463 left, top, width, height,
1464 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001465}
1466
1467void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001468 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001470 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001471
1472 // TODO: when underlying api has a direct way to do this we should use it
1473 // (e.g. glDrawPixels on desktop GL).
1474
bsalomon@google.com5c638652011-07-18 19:31:59 +00001475 this->flush(true);
1476
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001477 const GrTextureDesc desc = {
1478 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001479 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001480 GrAutoScratchTexture ast(this, desc);
1481 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001482 if (NULL == texture) {
1483 return;
1484 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001485 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001486
bsalomon@google.com27847de2011-02-22 20:59:41 +00001487 GrDrawTarget::AutoStateRestore asr(fGpu);
1488
1489 GrMatrix matrix;
1490 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1491 fGpu->setViewMatrix(matrix);
1492
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001493 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1495 fGpu->setAlpha(0xFF);
1496 fGpu->setBlendFunc(kOne_BlendCoeff,
1497 kZero_BlendCoeff);
1498 fGpu->setTexture(0, texture);
1499
1500 GrSamplerState sampler;
1501 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001502 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001503 sampler.setMatrix(matrix);
1504 fGpu->setSamplerState(0, sampler);
1505
1506 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1507 static const int VCOUNT = 4;
1508
1509 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1510 if (!geo.succeeded()) {
1511 return;
1512 }
1513 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1514 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1515}
1516////////////////////////////////////////////////////////////////////////////////
1517
1518void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001519
1520 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1521 int s = i + GrPaint::kFirstTextureStage;
1522 target->setTexture(s, paint.getTexture(i));
1523 target->setSamplerState(s, *paint.getTextureSampler(i));
1524 }
1525
1526 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1527
1528 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1529 int s = i + GrPaint::kFirstMaskStage;
1530 target->setTexture(s, paint.getMask(i));
1531 target->setSamplerState(s, *paint.getMaskSampler(i));
1532 }
1533
bsalomon@google.com27847de2011-02-22 20:59:41 +00001534 target->setColor(paint.fColor);
1535
1536 if (paint.fDither) {
1537 target->enableState(GrDrawTarget::kDither_StateBit);
1538 } else {
1539 target->disableState(GrDrawTarget::kDither_StateBit);
1540 }
1541 if (paint.fAntiAlias) {
1542 target->enableState(GrDrawTarget::kAntialias_StateBit);
1543 } else {
1544 target->disableState(GrDrawTarget::kAntialias_StateBit);
1545 }
1546 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001547 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001548}
1549
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001550GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001551 DrawCategory category) {
1552 if (category != fLastDrawCategory) {
1553 flushDrawBuffer();
1554 fLastDrawCategory = category;
1555 }
1556 SetPaint(paint, fGpu);
1557 GrDrawTarget* target = fGpu;
1558 switch (category) {
1559 case kText_DrawCategory:
1560#if DEFER_TEXT_RENDERING
1561 target = fDrawBuffer;
1562 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1563#else
1564 target = fGpu;
1565#endif
1566 break;
1567 case kUnbuffered_DrawCategory:
1568 target = fGpu;
1569 break;
1570 case kBuffered_DrawCategory:
1571 target = fDrawBuffer;
1572 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1573 break;
1574 }
1575 return target;
1576}
1577
1578////////////////////////////////////////////////////////////////////////////////
1579
bsalomon@google.com27847de2011-02-22 20:59:41 +00001580void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001581 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001582 fGpu->setRenderTarget(target);
1583}
1584
1585GrRenderTarget* GrContext::getRenderTarget() {
1586 return fGpu->getRenderTarget();
1587}
1588
1589const GrRenderTarget* GrContext::getRenderTarget() const {
1590 return fGpu->getRenderTarget();
1591}
1592
1593const GrMatrix& GrContext::getMatrix() const {
1594 return fGpu->getViewMatrix();
1595}
1596
1597void GrContext::setMatrix(const GrMatrix& m) {
1598 fGpu->setViewMatrix(m);
1599}
1600
1601void GrContext::concatMatrix(const GrMatrix& m) const {
1602 fGpu->preConcatViewMatrix(m);
1603}
1604
1605static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1606 intptr_t mask = 1 << shift;
1607 if (pred) {
1608 bits |= mask;
1609 } else {
1610 bits &= ~mask;
1611 }
1612 return bits;
1613}
1614
1615void GrContext::resetStats() {
1616 fGpu->resetStats();
1617}
1618
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001619const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001620 return fGpu->getStats();
1621}
1622
1623void GrContext::printStats() const {
1624 fGpu->printStats();
1625}
1626
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001627GrContext::GrContext(GrGpu* gpu) :
1628 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1629 gpu->supportsStencilWrapOps()) {
1630
bsalomon@google.com27847de2011-02-22 20:59:41 +00001631 fGpu = gpu;
1632 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001633 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001634
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001635 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1636 fGpu->setClipPathRenderer(fCustomPathRenderer);
1637
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001638 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1639 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001640 fFontCache = new GrFontCache(fGpu);
1641
1642 fLastDrawCategory = kUnbuffered_DrawCategory;
1643
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001644 fDrawBuffer = NULL;
1645 fDrawBufferVBAllocPool = NULL;
1646 fDrawBufferIBAllocPool = NULL;
1647
bsalomon@google.com205d4602011-04-25 12:43:45 +00001648 fAAFillRectIndexBuffer = NULL;
1649 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001650
1651 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1652 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1653 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1654 }
1655 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001656
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001657 this->setupDrawBuffer();
1658}
1659
1660void GrContext::setupDrawBuffer() {
1661
1662 GrAssert(NULL == fDrawBuffer);
1663 GrAssert(NULL == fDrawBufferVBAllocPool);
1664 GrAssert(NULL == fDrawBufferIBAllocPool);
1665
bsalomon@google.com27847de2011-02-22 20:59:41 +00001666#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001667 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001668 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001669 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1670 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001671 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001672 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001673 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001674 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1675
1676 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1677 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001678#endif
1679
1680#if BATCH_RECT_TO_RECT
1681 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1682#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001683}
1684
bsalomon@google.com27847de2011-02-22 20:59:41 +00001685GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1686 GrDrawTarget* target;
1687#if DEFER_TEXT_RENDERING
1688 target = prepareToDraw(paint, kText_DrawCategory);
1689#else
1690 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1691#endif
1692 SetPaint(paint, target);
1693 return target;
1694}
1695
1696const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1697 return fGpu->getQuadIndexBuffer();
1698}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001699
bsalomon@google.comee435122011-07-01 14:57:55 +00001700GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001701 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001702 if (NULL != fCustomPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +00001703 fCustomPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001704 return fCustomPathRenderer;
1705 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +00001706 GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001707 return &fDefaultPathRenderer;
1708 }
1709}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001710
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001711void GrContext::convolveInX(GrTexture* texture,
1712 const SkRect& rect,
1713 const float* kernel,
1714 int kernelWidth) {
1715 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1716 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1717}
1718
1719void GrContext::convolveInY(GrTexture* texture,
1720 const SkRect& rect,
1721 const float* kernel,
1722 int kernelWidth) {
1723 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1724 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1725}
1726
1727void GrContext::convolve(GrTexture* texture,
1728 const SkRect& rect,
1729 float imageIncrement[2],
1730 const float* kernel,
1731 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001732 GrDrawTarget::AutoStateRestore asr(fGpu);
1733 GrMatrix sampleM;
1734 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1735 GrSamplerState::kClamp_WrapMode,
1736 GrSamplerState::kConvolution_Filter);
1737 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001738 sampleM.setScale(GR_Scalar1 / texture->width(),
1739 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001740 sampler.setMatrix(sampleM);
1741 fGpu->setSamplerState(0, sampler);
1742 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001743 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001744 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001745 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1746}