blob: bfae62e051149bab135b74c98b51a3718b23133d [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.com47370822011-08-02 15:29:38 +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);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000958 if (!geo.succeeded()) {
959 GrPrintf("Failed to get space for vertices!\n");
960 return;
961 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000962
963 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
964
965 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
966 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
967
968 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
969 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
970
971 verts += sizeof(GrPoint);
972 for (int i = 0; i < 4; ++i) {
973 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
974 }
975
976 GrColor innerColor = getColorForMesh(paint);
977 verts += 4 * vsize;
978 for (int i = 0; i < 4; ++i) {
979 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
980 }
981
982 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
983
984 target->drawIndexed(kTriangles_PrimitiveType, 0,
985 0, 8, this->aaFillRectIndexCount());
986}
987
988void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
989 const GrRect& devRect, const GrVec& devStrokeSize) {
990 const GrScalar& dx = devStrokeSize.fX;
991 const GrScalar& dy = devStrokeSize.fY;
992 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
993 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
994
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000995 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
996 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000997
998 GrScalar spare;
999 {
1000 GrScalar w = devRect.width() - dx;
1001 GrScalar h = devRect.height() - dy;
1002 spare = GrMin(w, h);
1003 }
1004
1005 if (spare <= 0) {
1006 GrRect r(devRect);
1007 r.inset(-rx, -ry);
1008 fillAARect(target, paint, r);
1009 return;
1010 }
1011
1012 size_t vsize = GrDrawTarget::VertexSize(layout);
1013
1014 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001015 if (!geo.succeeded()) {
1016 GrPrintf("Failed to get space for vertices!\n");
1017 return;
1018 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001019
1020 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1021
1022 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1023 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1024 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1025 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1026
1027 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1028 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1029 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1030 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1031
1032 verts += sizeof(GrPoint);
1033 for (int i = 0; i < 4; ++i) {
1034 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1035 }
1036
1037 GrColor innerColor = getColorForMesh(paint);
1038 verts += 4 * vsize;
1039 for (int i = 0; i < 8; ++i) {
1040 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1041 }
1042
1043 verts += 8 * vsize;
1044 for (int i = 0; i < 8; ++i) {
1045 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1046 }
1047
1048 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1049 target->drawIndexed(kTriangles_PrimitiveType,
1050 0, 0, 16, aaStrokeRectIndexCount());
1051}
1052
reed@google.com20efde72011-05-09 17:00:02 +00001053/**
1054 * Returns true if the rects edges are integer-aligned.
1055 */
1056static bool isIRect(const GrRect& r) {
1057 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1058 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1059}
1060
bsalomon@google.com205d4602011-04-25 12:43:45 +00001061static bool apply_aa_to_rect(GrDrawTarget* target,
1062 GrGpu* gpu,
1063 const GrPaint& paint,
1064 const GrRect& rect,
1065 GrScalar width,
1066 const GrMatrix* matrix,
1067 GrMatrix* combinedMatrix,
1068 GrRect* devRect) {
1069 // we use a simple alpha ramp to do aa on axis-aligned rects
1070 // do AA with alpha ramp if the caller requested AA, the rect
1071 // will be axis-aligned,the render target is not
1072 // multisampled, and the rect won't land on integer coords.
1073
1074 if (!paint.fAntiAlias) {
1075 return false;
1076 }
1077
1078 if (target->getRenderTarget()->isMultisampled()) {
1079 return false;
1080 }
1081
1082 if (0 == width && gpu->supportsAALines()) {
1083 return false;
1084 }
1085
1086 if (!target->getViewMatrix().preservesAxisAlignment()) {
1087 return false;
1088 }
1089
1090 if (NULL != matrix &&
1091 !matrix->preservesAxisAlignment()) {
1092 return false;
1093 }
1094
1095 *combinedMatrix = target->getViewMatrix();
1096 if (NULL != matrix) {
1097 combinedMatrix->preConcat(*matrix);
1098 GrAssert(combinedMatrix->preservesAxisAlignment());
1099 }
1100
1101 combinedMatrix->mapRect(devRect, rect);
1102 devRect->sort();
1103
1104 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001105 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001106 } else {
1107 return true;
1108 }
1109}
1110
bsalomon@google.com27847de2011-02-22 20:59:41 +00001111void GrContext::drawRect(const GrPaint& paint,
1112 const GrRect& rect,
1113 GrScalar width,
1114 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001115 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001116
1117 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001118 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001119
bsalomon@google.com205d4602011-04-25 12:43:45 +00001120 GrRect devRect = rect;
1121 GrMatrix combinedMatrix;
1122 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1123 &combinedMatrix, &devRect);
1124
1125 if (doAA) {
1126 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001127 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001128 GrMatrix inv;
1129 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001130 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001131 }
1132 }
1133 target->setViewMatrix(GrMatrix::I());
1134 if (width >= 0) {
1135 GrVec strokeSize;;
1136 if (width > 0) {
1137 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001138 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001139 strokeSize.setAbs(strokeSize);
1140 } else {
1141 strokeSize.set(GR_Scalar1, GR_Scalar1);
1142 }
1143 strokeAARect(target, paint, devRect, strokeSize);
1144 } else {
1145 fillAARect(target, paint, devRect);
1146 }
1147 return;
1148 }
1149
bsalomon@google.com27847de2011-02-22 20:59:41 +00001150 if (width >= 0) {
1151 // TODO: consider making static vertex buffers for these cases.
1152 // Hairline could be done by just adding closing vertex to
1153 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001154 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1155
bsalomon@google.com27847de2011-02-22 20:59:41 +00001156 static const int worstCaseVertCount = 10;
1157 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1158
1159 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001160 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001161 return;
1162 }
1163
1164 GrPrimitiveType primType;
1165 int vertCount;
1166 GrPoint* vertex = geo.positions();
1167
1168 if (width > 0) {
1169 vertCount = 10;
1170 primType = kTriangleStrip_PrimitiveType;
1171 setStrokeRectStrip(vertex, rect, width);
1172 } else {
1173 // hairline
1174 vertCount = 5;
1175 primType = kLineStrip_PrimitiveType;
1176 vertex[0].set(rect.fLeft, rect.fTop);
1177 vertex[1].set(rect.fRight, rect.fTop);
1178 vertex[2].set(rect.fRight, rect.fBottom);
1179 vertex[3].set(rect.fLeft, rect.fBottom);
1180 vertex[4].set(rect.fLeft, rect.fTop);
1181 }
1182
1183 GrDrawTarget::AutoViewMatrixRestore avmr;
1184 if (NULL != matrix) {
1185 avmr.set(target);
1186 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001187 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001188 }
1189
1190 target->drawNonIndexed(primType, 0, vertCount);
1191 } else {
1192 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001193 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001194 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1195 if (NULL == sqVB) {
1196 GrPrintf("Failed to create static rect vb.\n");
1197 return;
1198 }
1199 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001200 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1201 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001202 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001203 0, rect.height(), rect.fTop,
1204 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001205
1206 if (NULL != matrix) {
1207 m.postConcat(*matrix);
1208 }
1209
1210 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001211 target->preConcatSamplerMatrices(stageMask, m);
1212
bsalomon@google.com27847de2011-02-22 20:59:41 +00001213 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1214 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001215 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001216 #endif
1217 }
1218}
1219
1220void GrContext::drawRectToRect(const GrPaint& paint,
1221 const GrRect& dstRect,
1222 const GrRect& srcRect,
1223 const GrMatrix* dstMatrix,
1224 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001225 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001226
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001227 // srcRect refers to paint's first texture
1228 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001229 drawRect(paint, dstRect, -1, dstMatrix);
1230 return;
1231 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001232
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1234
1235#if GR_STATIC_RECT_VB
1236 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001237
1238 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001239 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1240
1241 GrMatrix m;
1242
1243 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1244 0, dstRect.height(), dstRect.fTop,
1245 0, 0, GrMatrix::I()[8]);
1246 if (NULL != dstMatrix) {
1247 m.postConcat(*dstMatrix);
1248 }
1249 target->preConcatViewMatrix(m);
1250
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001251 // srcRect refers to first stage
1252 int otherStageMask = paint.getActiveStageMask() &
1253 (~(1 << GrPaint::kFirstTextureStage));
1254 if (otherStageMask) {
1255 target->preConcatSamplerMatrices(otherStageMask, m);
1256 }
1257
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1259 0, srcRect.height(), srcRect.fTop,
1260 0, 0, GrMatrix::I()[8]);
1261 if (NULL != srcMatrix) {
1262 m.postConcat(*srcMatrix);
1263 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001264 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001266 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1267 if (NULL == sqVB) {
1268 GrPrintf("Failed to create static rect vb.\n");
1269 return;
1270 }
1271 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001272 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1273#else
1274
1275 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001276#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001277 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001278#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001279 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1280#endif
1281
1282 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1283 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1284 srcRects[0] = &srcRect;
1285 srcMatrices[0] = srcMatrix;
1286
1287 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1288#endif
1289}
1290
1291void GrContext::drawVertices(const GrPaint& paint,
1292 GrPrimitiveType primitiveType,
1293 int vertexCount,
1294 const GrPoint positions[],
1295 const GrPoint texCoords[],
1296 const GrColor colors[],
1297 const uint16_t indices[],
1298 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001299 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300
1301 GrDrawTarget::AutoReleaseGeometry geo;
1302
1303 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1304
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001305 bool hasTexCoords[GrPaint::kTotalStages] = {
1306 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1307 0 // remaining stages use positions
1308 };
1309
1310 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001311
1312 if (NULL != colors) {
1313 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001315 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001316
1317 if (sizeof(GrPoint) != vertexSize) {
1318 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001319 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001320 return;
1321 }
1322 int texOffsets[GrDrawTarget::kMaxTexCoords];
1323 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001324 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1325 texOffsets,
1326 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327 void* curVertex = geo.vertices();
1328
1329 for (int i = 0; i < vertexCount; ++i) {
1330 *((GrPoint*)curVertex) = positions[i];
1331
1332 if (texOffsets[0] > 0) {
1333 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1334 }
1335 if (colorOffset > 0) {
1336 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1337 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001338 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001339 }
1340 } else {
1341 target->setVertexSourceToArray(layout, positions, vertexCount);
1342 }
1343
bsalomon@google.com91958362011-06-13 17:58:13 +00001344 // we don't currently apply offscreen AA to this path. Need improved
1345 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001346
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001347 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001348 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001349 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001350 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001351 target->drawNonIndexed(primitiveType, 0, vertexCount);
1352 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001353}
1354
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001355///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001356
reed@google.com07f3ee12011-05-16 17:21:57 +00001357void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1358 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001359
bsalomon@google.com27847de2011-02-22 20:59:41 +00001360 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comee435122011-07-01 14:57:55 +00001361 GrPathRenderer* pr = this->getPathRenderer(path, fill);
1362 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1363 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001364
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001365 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001366 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001367
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001368 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001369
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001370 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001371 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1372 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001373 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001374 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001375 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001376 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001377 return;
1378 }
1379 }
reed@google.com70c136e2011-06-03 19:51:26 +00001380
reed@google.com07f3ee12011-05-16 17:21:57 +00001381 GrRect pathBounds = path.getBounds();
1382 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001383 if (NULL != translate) {
1384 pathBounds.offset(*translate);
1385 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001386 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001387 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001388 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001389 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001390 return;
1391 }
1392 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001393 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001394 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1395 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001396 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1397 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1398 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001399 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001400 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1401 }
1402 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001403 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001404 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001405 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1406 GrRect rect;
1407 if (clipIBounds.fTop < bound.fTop) {
1408 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1409 clipIBounds.fRight, bound.fTop);
1410 target->drawSimpleRect(rect, NULL, stageMask);
1411 }
1412 if (clipIBounds.fLeft < bound.fLeft) {
1413 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1414 bound.fLeft, bound.fBottom);
1415 target->drawSimpleRect(rect, NULL, stageMask);
1416 }
1417 if (clipIBounds.fRight > bound.fRight) {
1418 rect.setLTRB(bound.fRight, bound.fTop,
1419 clipIBounds.fRight, bound.fBottom);
1420 target->drawSimpleRect(rect, NULL, stageMask);
1421 }
1422 if (clipIBounds.fBottom > bound.fBottom) {
1423 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1424 clipIBounds.fRight, clipIBounds.fBottom);
1425 target->drawSimpleRect(rect, NULL, stageMask);
1426 }
1427 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001428 return;
1429 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001430 }
1431 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001432}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001433
bsalomon@google.com27847de2011-02-22 20:59:41 +00001434////////////////////////////////////////////////////////////////////////////////
1435
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001436void GrContext::flush(int flagsBitfield) {
1437 if (kDiscard_FlushBit & flagsBitfield) {
1438 fDrawBuffer->reset();
1439 } else {
1440 flushDrawBuffer();
1441 }
1442
1443 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001444 fGpu->forceRenderTargetFlush();
1445 }
1446}
1447
1448void GrContext::flushText() {
1449 if (kText_DrawCategory == fLastDrawCategory) {
1450 flushDrawBuffer();
1451 }
1452}
1453
1454void GrContext::flushDrawBuffer() {
1455#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001456 if (fDrawBuffer) {
1457 fDrawBuffer->playback(fGpu);
1458 fDrawBuffer->reset();
1459 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460#endif
1461}
1462
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001463bool GrContext::readTexturePixels(GrTexture* texture,
1464 int left, int top, int width, int height,
1465 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001466 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001467
1468 // TODO: code read pixels for textures that aren't rendertargets
1469
1470 this->flush();
1471 GrRenderTarget* target = texture->asRenderTarget();
1472 if (NULL != target) {
1473 return fGpu->readPixels(target,
1474 left, top, width, height,
1475 config, buffer);
1476 } else {
1477 return false;
1478 }
1479}
1480
1481bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1482 int left, int top, int width, int height,
1483 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001484 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001485 uint32_t flushFlags = 0;
1486 if (NULL == target) {
1487 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1488 }
1489
1490 this->flush(flushFlags);
1491 return fGpu->readPixels(target,
1492 left, top, width, height,
1493 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494}
1495
1496void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001497 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001499 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001500
1501 // TODO: when underlying api has a direct way to do this we should use it
1502 // (e.g. glDrawPixels on desktop GL).
1503
bsalomon@google.com5c638652011-07-18 19:31:59 +00001504 this->flush(true);
1505
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001506 const GrTextureDesc desc = {
1507 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001508 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001509 GrAutoScratchTexture ast(this, desc);
1510 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001511 if (NULL == texture) {
1512 return;
1513 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001514 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001515
bsalomon@google.com27847de2011-02-22 20:59:41 +00001516 GrDrawTarget::AutoStateRestore asr(fGpu);
1517
1518 GrMatrix matrix;
1519 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1520 fGpu->setViewMatrix(matrix);
1521
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001522 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001523 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1524 fGpu->setAlpha(0xFF);
1525 fGpu->setBlendFunc(kOne_BlendCoeff,
1526 kZero_BlendCoeff);
1527 fGpu->setTexture(0, texture);
1528
1529 GrSamplerState sampler;
1530 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001531 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001532 sampler.setMatrix(matrix);
1533 fGpu->setSamplerState(0, sampler);
1534
1535 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1536 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001537 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001538 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1539 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001540 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001541 return;
1542 }
1543 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1544 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1545}
1546////////////////////////////////////////////////////////////////////////////////
1547
1548void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001549
1550 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1551 int s = i + GrPaint::kFirstTextureStage;
1552 target->setTexture(s, paint.getTexture(i));
1553 target->setSamplerState(s, *paint.getTextureSampler(i));
1554 }
1555
1556 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1557
1558 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1559 int s = i + GrPaint::kFirstMaskStage;
1560 target->setTexture(s, paint.getMask(i));
1561 target->setSamplerState(s, *paint.getMaskSampler(i));
1562 }
1563
bsalomon@google.com27847de2011-02-22 20:59:41 +00001564 target->setColor(paint.fColor);
1565
1566 if (paint.fDither) {
1567 target->enableState(GrDrawTarget::kDither_StateBit);
1568 } else {
1569 target->disableState(GrDrawTarget::kDither_StateBit);
1570 }
1571 if (paint.fAntiAlias) {
1572 target->enableState(GrDrawTarget::kAntialias_StateBit);
1573 } else {
1574 target->disableState(GrDrawTarget::kAntialias_StateBit);
1575 }
1576 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001577 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001578}
1579
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001580GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001581 DrawCategory category) {
1582 if (category != fLastDrawCategory) {
1583 flushDrawBuffer();
1584 fLastDrawCategory = category;
1585 }
1586 SetPaint(paint, fGpu);
1587 GrDrawTarget* target = fGpu;
1588 switch (category) {
1589 case kText_DrawCategory:
1590#if DEFER_TEXT_RENDERING
1591 target = fDrawBuffer;
1592 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1593#else
1594 target = fGpu;
1595#endif
1596 break;
1597 case kUnbuffered_DrawCategory:
1598 target = fGpu;
1599 break;
1600 case kBuffered_DrawCategory:
1601 target = fDrawBuffer;
1602 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1603 break;
1604 }
1605 return target;
1606}
1607
1608////////////////////////////////////////////////////////////////////////////////
1609
bsalomon@google.com27847de2011-02-22 20:59:41 +00001610void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001611 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001612 fGpu->setRenderTarget(target);
1613}
1614
1615GrRenderTarget* GrContext::getRenderTarget() {
1616 return fGpu->getRenderTarget();
1617}
1618
1619const GrRenderTarget* GrContext::getRenderTarget() const {
1620 return fGpu->getRenderTarget();
1621}
1622
1623const GrMatrix& GrContext::getMatrix() const {
1624 return fGpu->getViewMatrix();
1625}
1626
1627void GrContext::setMatrix(const GrMatrix& m) {
1628 fGpu->setViewMatrix(m);
1629}
1630
1631void GrContext::concatMatrix(const GrMatrix& m) const {
1632 fGpu->preConcatViewMatrix(m);
1633}
1634
1635static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1636 intptr_t mask = 1 << shift;
1637 if (pred) {
1638 bits |= mask;
1639 } else {
1640 bits &= ~mask;
1641 }
1642 return bits;
1643}
1644
1645void GrContext::resetStats() {
1646 fGpu->resetStats();
1647}
1648
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001649const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001650 return fGpu->getStats();
1651}
1652
1653void GrContext::printStats() const {
1654 fGpu->printStats();
1655}
1656
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001657GrContext::GrContext(GrGpu* gpu) :
1658 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1659 gpu->supportsStencilWrapOps()) {
1660
bsalomon@google.com27847de2011-02-22 20:59:41 +00001661 fGpu = gpu;
1662 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001663 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001664
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001665 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1666 fGpu->setClipPathRenderer(fCustomPathRenderer);
1667
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001668 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1669 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001670 fFontCache = new GrFontCache(fGpu);
1671
1672 fLastDrawCategory = kUnbuffered_DrawCategory;
1673
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001674 fDrawBuffer = NULL;
1675 fDrawBufferVBAllocPool = NULL;
1676 fDrawBufferIBAllocPool = NULL;
1677
bsalomon@google.com205d4602011-04-25 12:43:45 +00001678 fAAFillRectIndexBuffer = NULL;
1679 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001680
1681 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1682 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1683 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1684 }
1685 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001686
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001687 this->setupDrawBuffer();
1688}
1689
1690void GrContext::setupDrawBuffer() {
1691
1692 GrAssert(NULL == fDrawBuffer);
1693 GrAssert(NULL == fDrawBufferVBAllocPool);
1694 GrAssert(NULL == fDrawBufferIBAllocPool);
1695
bsalomon@google.com27847de2011-02-22 20:59:41 +00001696#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001697 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001698 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001699 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1700 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001701 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001702 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001703 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001704 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1705
1706 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1707 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001708#endif
1709
1710#if BATCH_RECT_TO_RECT
1711 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1712#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001713}
1714
bsalomon@google.com27847de2011-02-22 20:59:41 +00001715GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1716 GrDrawTarget* target;
1717#if DEFER_TEXT_RENDERING
1718 target = prepareToDraw(paint, kText_DrawCategory);
1719#else
1720 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1721#endif
1722 SetPaint(paint, target);
1723 return target;
1724}
1725
1726const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1727 return fGpu->getQuadIndexBuffer();
1728}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001729
bsalomon@google.comee435122011-07-01 14:57:55 +00001730GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001731 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001732 if (NULL != fCustomPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +00001733 fCustomPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001734 return fCustomPathRenderer;
1735 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +00001736 GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001737 return &fDefaultPathRenderer;
1738 }
1739}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001740
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001741void GrContext::convolveInX(GrTexture* texture,
1742 const SkRect& rect,
1743 const float* kernel,
1744 int kernelWidth) {
1745 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1746 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1747}
1748
1749void GrContext::convolveInY(GrTexture* texture,
1750 const SkRect& rect,
1751 const float* kernel,
1752 int kernelWidth) {
1753 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1754 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1755}
1756
1757void GrContext::convolve(GrTexture* texture,
1758 const SkRect& rect,
1759 float imageIncrement[2],
1760 const float* kernel,
1761 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001762 GrDrawTarget::AutoStateRestore asr(fGpu);
1763 GrMatrix sampleM;
1764 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1765 GrSamplerState::kClamp_WrapMode,
1766 GrSamplerState::kConvolution_Filter);
1767 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001768 sampleM.setScale(GR_Scalar1 / texture->width(),
1769 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001770 sampler.setMatrix(sampleM);
1771 fGpu->setSamplerState(0, sampler);
1772 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001773 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001774 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001775 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1776}