blob: 506cb9f365ea8cfc4e6c19f53595d9f3c8a7d5c2 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000021#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000022
bsalomon@google.com91958362011-06-13 17:58:13 +000023// Using MSAA seems to be slower for some yet unknown reason.
24#define PREFER_MSAA_OFFSCREEN_AA 0
25#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000026
bsalomon@google.com27847de2011-02-22 20:59:41 +000027#define DEFER_TEXT_RENDERING 1
28
29#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
30
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000031static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
32static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000033
34static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
35static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
36
37// We are currently only batching Text and drawRectToRect, both
38// of which use the quad index buffer.
39static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
40static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
41
bsalomon@google.com05ef5102011-05-02 21:14:59 +000042GrContext* GrContext::Create(GrEngine engine,
43 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000044 GrContext* ctx = NULL;
45 GrGpu* fGpu = GrGpu::Create(engine, context3D);
46 if (NULL != fGpu) {
47 ctx = new GrContext(fGpu);
48 fGpu->unref();
49 }
50 return ctx;
51}
52
53GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000054 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000055}
56
57GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000058 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000059 delete fTextureCache;
60 delete fFontCache;
61 delete fDrawBuffer;
62 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000063 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000064
bsalomon@google.com205d4602011-04-25 12:43:45 +000065 GrSafeUnref(fAAFillRectIndexBuffer);
66 GrSafeUnref(fAAStrokeRectIndexBuffer);
67 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000068 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000069}
70
bsalomon@google.com8fe72472011-03-30 21:26:44 +000071void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000072 contextDestroyed();
73 this->setupDrawBuffer();
74}
75
76void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000077 // abandon first to so destructors
78 // don't try to free the resources in the API.
79 fGpu->abandonResources();
80
bsalomon@google.com30085192011-08-19 15:42:31 +000081 // a path renderer may be holding onto resources that
82 // are now unusable
83 GrSafeSetNull(fPathRendererChain);
84
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBuffer;
86 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000087
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBufferVBAllocPool;
89 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferIBAllocPool;
92 fDrawBufferIBAllocPool = NULL;
93
bsalomon@google.com205d4602011-04-25 12:43:45 +000094 GrSafeSetNull(fAAFillRectIndexBuffer);
95 GrSafeSetNull(fAAStrokeRectIndexBuffer);
96
bsalomon@google.com8fe72472011-03-30 21:26:44 +000097 fTextureCache->removeAll();
98 fFontCache->freeAll();
99 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100}
101
102void GrContext::resetContext() {
103 fGpu->markContextDirty();
104}
105
106void GrContext::freeGpuResources() {
107 this->flush();
108 fTextureCache->removeAll();
109 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000110 // a path renderer may be holding onto resources
111 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000112}
113
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000114////////////////////////////////////////////////////////////////////////////////
115
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000116int GrContext::PaintStageVertexLayoutBits(
117 const GrPaint& paint,
118 const bool hasTexCoords[GrPaint::kTotalStages]) {
119 int stageMask = paint.getActiveStageMask();
120 int layout = 0;
121 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
122 if ((1 << i) & stageMask) {
123 if (NULL != hasTexCoords && hasTexCoords[i]) {
124 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
125 } else {
126 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
127 }
128 }
129 }
130 return layout;
131}
132
133
134////////////////////////////////////////////////////////////////////////////////
135
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000136enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000137 // flags for textures
138 kNPOTBit = 0x1,
139 kFilterBit = 0x2,
140 kScratchBit = 0x4,
141
142 // resource type
143 kTextureBit = 0x8,
144 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000145};
146
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000147GrTexture* GrContext::TextureCacheEntry::texture() const {
148 if (NULL == fEntry) {
149 return NULL;
150 } else {
151 return (GrTexture*) fEntry->resource();
152 }
153}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000154
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000155namespace {
156// returns true if this is a "special" texture because of gpu NPOT limitations
157bool gen_texture_key_values(const GrGpu* gpu,
158 const GrSamplerState& sampler,
159 GrContext::TextureKey clientKey,
160 int width,
161 int height,
162 bool scratch,
163 uint32_t v[4]) {
164 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
165 // we assume we only need 16 bits of width and height
166 // assert that texture creation will fail anyway if this assumption
167 // would cause key collisions.
168 GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
169 v[0] = clientKey & 0xffffffffUL;
170 v[1] = (clientKey >> 32) & 0xffffffffUL;
171 v[2] = width | (height << 16);
172
173 v[3] = 0;
174 if (!gpu->npotTextureTileSupport()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000175 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
176
177 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
178 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
179
180 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000181 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000182 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000183 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184 }
185 }
186 }
187
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 if (scratch) {
189 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000190 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000192 v[3] |= kTextureBit;
193
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194 return v[3] & kNPOTBit;
195}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000196
197// we should never have more than one stencil buffer with same combo of
198// (width,height,samplecount)
199void gen_stencil_key_values(int width, int height,
200 int sampleCnt, uint32_t v[4]) {
201 v[0] = width;
202 v[1] = height;
203 v[2] = sampleCnt;
204 v[3] = kStencilBufferBit;
205}
206
207void gen_stencil_key_values(const GrStencilBuffer* sb,
208 uint32_t v[4]) {
209 gen_stencil_key_values(sb->width(), sb->height(),
210 sb->numSamples(), v);
211}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000212}
213
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000214GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
215 int width,
216 int height,
217 const GrSamplerState& sampler) {
218 uint32_t v[4];
219 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
220 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000221 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
222 GrResourceCache::kNested_LockType));
223}
224
225GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
226 uint32_t v[4];
227 gen_stencil_key_values(sb, v);
228 GrResourceKey resourceKey(v);
229 return fTextureCache->createAndLock(resourceKey, sb);
230}
231
232GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
233 int sampleCnt) {
234 uint32_t v[4];
235 gen_stencil_key_values(width, height, sampleCnt, v);
236 GrResourceKey resourceKey(v);
237 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
238 GrResourceCache::kSingle_LockType);
239 if (NULL != entry) {
240 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
241 return sb;
242 } else {
243 return NULL;
244 }
245}
246
247void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
248 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000249}
250
251static void stretchImage(void* dst,
252 int dstW,
253 int dstH,
254 void* src,
255 int srcW,
256 int srcH,
257 int bpp) {
258 GrFixed dx = (srcW << 16) / dstW;
259 GrFixed dy = (srcH << 16) / dstH;
260
261 GrFixed y = dy >> 1;
262
263 int dstXLimit = dstW*bpp;
264 for (int j = 0; j < dstH; ++j) {
265 GrFixed x = dx >> 1;
266 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
267 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
268 for (int i = 0; i < dstXLimit; i += bpp) {
269 memcpy((uint8_t*) dstRow + i,
270 (uint8_t*) srcRow + (x>>16)*bpp,
271 bpp);
272 x += dx;
273 }
274 y += dy;
275 }
276}
277
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000278GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000279 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000280 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000281 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000282 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000283
284#if GR_DUMP_TEXTURE_UPLOAD
285 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
286#endif
287
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000288 TextureCacheEntry entry;
289 uint32_t v[4];
290 bool special = gen_texture_key_values(fGpu, sampler, key,
291 desc.fWidth, desc.fHeight, false, v);
292 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000293
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000294 if (special) {
295 TextureCacheEntry clampEntry =
296 findAndLockTexture(key, desc.fWidth, desc.fHeight,
297 GrSamplerState::ClampNoFilter());
298
299 if (NULL == clampEntry.texture()) {
300 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000301 GrSamplerState::ClampNoFilter(),
302 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000303 GrAssert(NULL != clampEntry.texture());
304 if (NULL == clampEntry.texture()) {
305 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000306 }
307 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000308 GrTextureDesc rtDesc = desc;
309 rtDesc.fFlags = rtDesc.fFlags |
310 kRenderTarget_GrTextureFlagBit |
311 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000312 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
313 fGpu->minRenderTargetWidth()));
314 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
315 fGpu->minRenderTargetHeight()));
316
317 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
318
319 if (NULL != texture) {
320 GrDrawTarget::AutoStateRestore asr(fGpu);
321 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000322 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000323 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000324 fGpu->setViewMatrix(GrMatrix::I());
325 fGpu->setAlpha(0xff);
326 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
327 fGpu->disableState(GrDrawTarget::kDither_StateBit |
328 GrDrawTarget::kClip_StateBit |
329 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000330 GrSamplerState::Filter filter;
331 // if filtering is not desired then we want to ensure all
332 // texels in the resampled image are copies of texels from
333 // the original.
334 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
335 filter = GrSamplerState::kNearest_Filter;
336 } else {
337 filter = GrSamplerState::kBilinear_Filter;
338 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000339 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
340 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000341 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000342 fGpu->setSamplerState(0, stretchSampler);
343
344 static const GrVertexLayout layout =
345 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
346 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
347
348 if (arg.succeeded()) {
349 GrPoint* verts = (GrPoint*) arg.vertices();
350 verts[0].setIRectFan(0, 0,
351 texture->width(),
352 texture->height(),
353 2*sizeof(GrPoint));
354 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
355 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
356 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000357 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000358 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000359 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000360 } else {
361 // TODO: Our CPU stretch doesn't filter. But we create separate
362 // stretched textures when the sampler state is either filtered or
363 // not. Either implement filtered stretch blit on CPU or just create
364 // one when FBO case fails.
365
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000366 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000367 // no longer need to clamp at min RT size.
368 rtDesc.fWidth = GrNextPow2(desc.fWidth);
369 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000370 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000371 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000372 rtDesc.fWidth *
373 rtDesc.fHeight);
374 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
375 srcData, desc.fWidth, desc.fHeight, bpp);
376
377 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
378
379 GrTexture* texture = fGpu->createTexture(rtDesc,
380 stretchedPixels.get(),
381 stretchedRowBytes);
382 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000383 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000384 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000385 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000386
387 } else {
388 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
389 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000390 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 }
392 }
393 return entry;
394}
395
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000396namespace {
397inline void gen_scratch_tex_key_values(const GrGpu* gpu,
398 const GrTextureDesc& desc,
399 uint32_t v[4]) {
400 // Instead of a client-provided key of the texture contents
401 // we create a key of from the descriptor.
402 GrContext::TextureKey descKey = desc.fAALevel |
403 (desc.fFlags << 8) |
404 ((uint64_t) desc.fFormat << 32);
405 // this code path isn't friendly to tiling with NPOT restricitons
406 // We just pass ClampNoFilter()
407 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
408 desc.fWidth, desc.fHeight, true, v);
409}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000410}
411
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412GrContext::TextureCacheEntry GrContext::lockScratchTexture(
413 const GrTextureDesc& inDesc,
414 ScratchTexMatch match) {
415
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000416 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000417 if (kExact_ScratchTexMatch != match) {
418 // bin by pow2 with a reasonable min
419 static const int MIN_SIZE = 256;
420 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
421 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
422 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000423
424 uint32_t p0 = desc.fFormat;
425 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
426
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000428 int origWidth = desc.fWidth;
429 int origHeight = desc.fHeight;
430 bool doubledW = false;
431 bool doubledH = false;
432
433 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 uint32_t v[4];
435 gen_scratch_tex_key_values(fGpu, desc, v);
436 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000437 entry = fTextureCache->findAndLock(key,
438 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000439 // if we miss, relax the fit of the flags...
440 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000442 break;
443 }
444 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
445 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
446 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
447 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
448 } else if (!doubledW) {
449 desc.fFlags = inDesc.fFlags;
450 desc.fWidth *= 2;
451 doubledW = true;
452 } else if (!doubledH) {
453 desc.fFlags = inDesc.fFlags;
454 desc.fWidth = origWidth;
455 desc.fHeight *= 2;
456 doubledH = true;
457 } else {
458 break;
459 }
460
461 } while (true);
462
463 if (NULL == entry) {
464 desc.fFlags = inDesc.fFlags;
465 desc.fWidth = origWidth;
466 desc.fHeight = origHeight;
467 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
468 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000469 uint32_t v[4];
470 gen_scratch_tex_key_values(fGpu, desc, v);
471 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000472 entry = fTextureCache->createAndLock(key, texture);
473 }
474 }
475
476 // If the caller gives us the same desc/sampler twice we don't want
477 // to return the same texture the second time (unless it was previously
478 // released). So we detach the entry from the cache and reattach at release.
479 if (NULL != entry) {
480 fTextureCache->detach(entry);
481 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000482 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000483}
484
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485void GrContext::unlockTexture(TextureCacheEntry entry) {
486 // If this is a scratch texture we detached it from the cache
487 // while it was locked (to avoid two callers simultaneously getting
488 // the same texture).
489 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
490 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000491 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000492 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000493 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000494}
495
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000496GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000497 void* srcData,
498 size_t rowBytes) {
499 return fGpu->createTexture(desc, srcData, rowBytes);
500}
501
502void GrContext::getTextureCacheLimits(int* maxTextures,
503 size_t* maxTextureBytes) const {
504 fTextureCache->getLimits(maxTextures, maxTextureBytes);
505}
506
507void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
508 fTextureCache->setLimits(maxTextures, maxTextureBytes);
509}
510
bsalomon@google.com91958362011-06-13 17:58:13 +0000511int GrContext::getMaxTextureSize() const {
512 return fGpu->maxTextureSize();
513}
514
515int GrContext::getMaxRenderTargetSize() const {
516 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000517}
518
519///////////////////////////////////////////////////////////////////////////////
520
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000521GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
522 // validate flags here so that GrGpu subclasses don't have to check
523 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
524 0 != desc.fRenderTargetFlags) {
525 return NULL;
526 }
bsalomon@google.com47370822011-08-02 15:29:38 +0000527#if !GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000528 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
529 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
530 return NULL;
531 }
532 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
533 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
534 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
535 return NULL;
536 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000537#else
538 if (desc.fSampleCnt &&
539 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
540 return NULL;
541 }
542 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
543 desc.fSampleCnt &&
544 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
545 return NULL;
546 }
547#endif
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000548 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000549}
550
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000551GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000552 return fGpu->createRenderTargetFrom3DApiState();
553}
554
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000555///////////////////////////////////////////////////////////////////////////////
556
bsalomon@google.com27847de2011-02-22 20:59:41 +0000557bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
558 int width, int height) {
559 if (!fGpu->supports8BitPalette()) {
560 return false;
561 }
562
563
564 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
565
566 if (!isPow2) {
567 if (!fGpu->npotTextureSupport()) {
568 return false;
569 }
570
571 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
572 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
573 if (tiled && !fGpu->npotTextureTileSupport()) {
574 return false;
575 }
576 }
577 return true;
578}
579
580////////////////////////////////////////////////////////////////////////////////
581
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000582const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
583
bsalomon@google.com27847de2011-02-22 20:59:41 +0000584void GrContext::setClip(const GrClip& clip) {
585 fGpu->setClip(clip);
586 fGpu->enableState(GrDrawTarget::kClip_StateBit);
587}
588
589void GrContext::setClip(const GrIRect& rect) {
590 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000591 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000592 fGpu->setClip(clip);
593}
594
595////////////////////////////////////////////////////////////////////////////////
596
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000597void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000598 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000599 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000600}
601
602void GrContext::drawPaint(const GrPaint& paint) {
603 // set rect to be big enough to fill the space, but not super-huge, so we
604 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000605 GrRect r;
606 r.setLTRB(0, 0,
607 GrIntToScalar(getRenderTarget()->width()),
608 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000609 GrMatrix inverse;
610 if (fGpu->getViewInverse(&inverse)) {
611 inverse.mapRect(&r);
612 } else {
613 GrPrintf("---- fGpu->getViewInverse failed\n");
614 }
615 this->drawRect(paint, r);
616}
617
bsalomon@google.com205d4602011-04-25 12:43:45 +0000618////////////////////////////////////////////////////////////////////////////////
619
bsalomon@google.com91958362011-06-13 17:58:13 +0000620struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000621 enum Downsample {
622 k4x4TwoPass_Downsample,
623 k4x4SinglePass_Downsample,
624 kFSAA_Downsample
625 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000626 int fTileSizeX;
627 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000628 int fTileCountX;
629 int fTileCountY;
630 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000631 GrAutoScratchTexture fOffscreen0;
632 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000633 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000634 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000635};
636
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000637bool GrContext::doOffscreenAA(GrDrawTarget* target,
638 const GrPaint& paint,
639 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000640#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000641 return false;
642#else
643 if (!paint.fAntiAlias) {
644 return false;
645 }
646 if (isLines && fGpu->supportsAALines()) {
647 return false;
648 }
649 if (target->getRenderTarget()->isMultisampled()) {
650 return false;
651 }
652 // we have to be sure that the blend equation is expressible
653 // as simple src / dst coeffecients when the source
654 // is already modulated by the coverage fraction.
655 // We could use dual-source blending to get the correct per-pixel
656 // dst coeffecient for the remaining cases.
657 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
658 kOne_BlendCoeff != paint.fDstBlendCoeff &&
659 kISA_BlendCoeff != paint.fDstBlendCoeff) {
660 return false;
661 }
662 return true;
663#endif
664}
665
bsalomon@google.com91958362011-06-13 17:58:13 +0000666bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000667 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000668 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000669 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000670 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000671
672 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000673
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000674 GrAssert(NULL == record->fOffscreen0.texture());
675 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000676 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000677
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000678 int boundW = boundRect.width();
679 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000680
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000681 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000682
683 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
684 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
685
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000686 if (requireStencil) {
687 desc.fFlags = kRenderTarget_GrTextureFlagBit;
688 } else {
689 desc.fFlags = kRenderTarget_GrTextureFlagBit |
690 kNoStencil_GrTextureFlagBit;
691 }
692
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000693 desc.fFormat = kRGBA_8888_GrPixelConfig;
694
bsalomon@google.com91958362011-06-13 17:58:13 +0000695 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000696 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000697 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000698 desc.fAALevel = kMed_GrAALevel;
699 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000700 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
701 OffscreenRecord::k4x4SinglePass_Downsample :
702 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000703 record->fScale = OFFSCREEN_SSAA_SCALE;
704 // both downsample paths assume this
705 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000706 desc.fAALevel = kNone_GrAALevel;
707 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000708 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
709 // of simple circles?
710 if (pr) {
711 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
712 }
713
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000714 desc.fWidth *= record->fScale;
715 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000716 record->fOffscreen0.set(this, desc);
717 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000718 return false;
719 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000720 // the approximate lookup might have given us some slop space, might as well
721 // use it when computing the tiles size.
722 // these are scale values, will adjust after considering
723 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000724 record->fTileSizeX = record->fOffscreen0.texture()->width();
725 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000726
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000727 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000728 desc.fWidth /= 2;
729 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000730 record->fOffscreen1.set(this, desc);
731 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000732 return false;
733 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000734 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000735 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000736 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000737 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000738 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000739 record->fTileSizeX /= record->fScale;
740 record->fTileSizeY /= record->fScale;
741
742 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
743 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
744
tomhudson@google.com237a4612011-07-19 15:44:00 +0000745 record->fClip = target->getClip();
746
bsalomon@google.com91958362011-06-13 17:58:13 +0000747 target->saveCurrentDrawState(&record->fSavedState);
748 return true;
749}
750
751void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
752 const GrIRect& boundRect,
753 int tileX, int tileY,
754 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000755
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000756 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000757 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000758
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000759 GrPaint tempPaint;
760 tempPaint.reset();
761 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000762 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000763
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000764 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000765 int left = boundRect.fLeft + tileX * record->fTileSizeX;
766 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000767 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000769 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000770 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000771 target->postConcatViewMatrix(scaleM);
772
bsalomon@google.com91958362011-06-13 17:58:13 +0000773 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000774 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000775 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000776 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000777 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
778 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000779 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000780#if 0
781 // visualize tile boundaries by setting edges of offscreen to white
782 // and interior to tranparent. black.
783 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000784
bsalomon@google.com91958362011-06-13 17:58:13 +0000785 static const int gOffset = 2;
786 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
787 record->fScale * w - gOffset,
788 record->fScale * h - gOffset);
789 target->clear(&clear2, 0x0);
790#else
791 target->clear(&clear, 0x0);
792#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000793}
794
bsalomon@google.com91958362011-06-13 17:58:13 +0000795void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000796 const GrPaint& paint,
797 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000798 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000799 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000800 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000801 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000802 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000803 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000804 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
805 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000806 tileRect.fRight = (tileX == record->fTileCountX-1) ?
807 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000808 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000809 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
810 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000811 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000812
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000813 GrSamplerState::Filter filter;
814 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
815 filter = GrSamplerState::k4x4Downsample_Filter;
816 } else {
817 filter = GrSamplerState::kBilinear_Filter;
818 }
819
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000820 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000821 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000822 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000823
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000824 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000825 int scale;
826
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000827 enum {
828 kOffscreenStage = GrPaint::kTotalStages,
829 };
830
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000831 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000832 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000833 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000834 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000835
836 // Do 2x2 downsample from first to second
837 target->setTexture(kOffscreenStage, src);
838 target->setRenderTarget(dst);
839 target->setViewMatrix(GrMatrix::I());
840 sampleM.setScale(scale * GR_Scalar1 / src->width(),
841 scale * GR_Scalar1 / src->height());
842 sampler.setMatrix(sampleM);
843 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000844 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
845 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000846 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
847
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000848 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000849 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000850 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000851 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000852 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000853 } else {
854 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
855 record->fDownsample);
856 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000857 }
858
bsalomon@google.com91958362011-06-13 17:58:13 +0000859 // setup for draw back to main RT, we use the original
860 // draw state setup by the caller plus an additional coverage
861 // stage to handle the AA resolve. Also, we use an identity
862 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000863 int stageMask = paint.getActiveStageMask();
864
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000865 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000866 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000867
868 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000869 GrMatrix invVM;
870 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000871 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 }
873 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000874 // This is important when tiling, otherwise second tile's
875 // pass 1 view matrix will be incorrect.
876 GrDrawTarget::AutoViewMatrixRestore avmr(target);
877
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000878 target->setViewMatrix(GrMatrix::I());
879
880 target->setTexture(kOffscreenStage, src);
881 sampleM.setScale(scale * GR_Scalar1 / src->width(),
882 scale * GR_Scalar1 / src->height());
883 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000884 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000885 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000886 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000887
reed@google.com20efde72011-05-09 17:00:02 +0000888 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000889 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000890 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000891 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000892}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000893
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000894void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
895 GrPathRenderer* pr,
896 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000897 if (pr) {
898 // Counterpart of scale() in prepareForOffscreenAA()
899 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
900 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000901 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000902}
903
904////////////////////////////////////////////////////////////////////////////////
905
bsalomon@google.com27847de2011-02-22 20:59:41 +0000906/* create a triangle strip that strokes the specified triangle. There are 8
907 unique vertices, but we repreat the last 2 to close up. Alternatively we
908 could use an indices array, and then only send 8 verts, but not sure that
909 would be faster.
910 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000911static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000912 GrScalar width) {
913 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000914 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000915
916 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
917 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
918 verts[2].set(rect.fRight - rad, rect.fTop + rad);
919 verts[3].set(rect.fRight + rad, rect.fTop - rad);
920 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
921 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
922 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
923 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
924 verts[8] = verts[0];
925 verts[9] = verts[1];
926}
927
bsalomon@google.com205d4602011-04-25 12:43:45 +0000928static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000929 // FIXME: This was copied from SkGpuDevice, seems like
930 // we should have already smeared a in caller if that
931 // is what is desired.
932 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000933 unsigned a = GrColorUnpackA(paint.fColor);
934 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000935 } else {
936 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000937 }
938}
939
940static void setInsetFan(GrPoint* pts, size_t stride,
941 const GrRect& r, GrScalar dx, GrScalar dy) {
942 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
943}
944
945static const uint16_t gFillAARectIdx[] = {
946 0, 1, 5, 5, 4, 0,
947 1, 2, 6, 6, 5, 1,
948 2, 3, 7, 7, 6, 2,
949 3, 0, 4, 4, 7, 3,
950 4, 5, 6, 6, 7, 4,
951};
952
953int GrContext::aaFillRectIndexCount() const {
954 return GR_ARRAY_COUNT(gFillAARectIdx);
955}
956
957GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
958 if (NULL == fAAFillRectIndexBuffer) {
959 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
960 false);
961 GrAssert(NULL != fAAFillRectIndexBuffer);
962#if GR_DEBUG
963 bool updated =
964#endif
965 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
966 sizeof(gFillAARectIdx));
967 GR_DEBUGASSERT(updated);
968 }
969 return fAAFillRectIndexBuffer;
970}
971
972static const uint16_t gStrokeAARectIdx[] = {
973 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
974 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
975 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
976 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
977
978 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
979 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
980 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
981 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
982
983 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
984 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
985 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
986 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
987};
988
989int GrContext::aaStrokeRectIndexCount() const {
990 return GR_ARRAY_COUNT(gStrokeAARectIdx);
991}
992
993GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
994 if (NULL == fAAStrokeRectIndexBuffer) {
995 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
996 false);
997 GrAssert(NULL != fAAStrokeRectIndexBuffer);
998#if GR_DEBUG
999 bool updated =
1000#endif
1001 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1002 sizeof(gStrokeAARectIdx));
1003 GR_DEBUGASSERT(updated);
1004 }
1005 return fAAStrokeRectIndexBuffer;
1006}
1007
1008void GrContext::fillAARect(GrDrawTarget* target,
1009 const GrPaint& paint,
1010 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001011 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1012 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001013
1014 size_t vsize = GrDrawTarget::VertexSize(layout);
1015
1016 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001017 if (!geo.succeeded()) {
1018 GrPrintf("Failed to get space for vertices!\n");
1019 return;
1020 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001021
1022 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1023
1024 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1025 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1026
1027 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1028 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1029
1030 verts += sizeof(GrPoint);
1031 for (int i = 0; i < 4; ++i) {
1032 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1033 }
1034
1035 GrColor innerColor = getColorForMesh(paint);
1036 verts += 4 * vsize;
1037 for (int i = 0; i < 4; ++i) {
1038 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1039 }
1040
1041 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
1042
1043 target->drawIndexed(kTriangles_PrimitiveType, 0,
1044 0, 8, this->aaFillRectIndexCount());
1045}
1046
1047void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1048 const GrRect& devRect, const GrVec& devStrokeSize) {
1049 const GrScalar& dx = devStrokeSize.fX;
1050 const GrScalar& dy = devStrokeSize.fY;
1051 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1052 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1053
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001054 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1055 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001056
1057 GrScalar spare;
1058 {
1059 GrScalar w = devRect.width() - dx;
1060 GrScalar h = devRect.height() - dy;
1061 spare = GrMin(w, h);
1062 }
1063
1064 if (spare <= 0) {
1065 GrRect r(devRect);
1066 r.inset(-rx, -ry);
1067 fillAARect(target, paint, r);
1068 return;
1069 }
1070
1071 size_t vsize = GrDrawTarget::VertexSize(layout);
1072
1073 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001074 if (!geo.succeeded()) {
1075 GrPrintf("Failed to get space for vertices!\n");
1076 return;
1077 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001078
1079 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1080
1081 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1082 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1083 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1084 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1085
1086 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1087 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1088 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1089 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1090
1091 verts += sizeof(GrPoint);
1092 for (int i = 0; i < 4; ++i) {
1093 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1094 }
1095
1096 GrColor innerColor = getColorForMesh(paint);
1097 verts += 4 * vsize;
1098 for (int i = 0; i < 8; ++i) {
1099 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1100 }
1101
1102 verts += 8 * vsize;
1103 for (int i = 0; i < 8; ++i) {
1104 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1105 }
1106
1107 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1108 target->drawIndexed(kTriangles_PrimitiveType,
1109 0, 0, 16, aaStrokeRectIndexCount());
1110}
1111
reed@google.com20efde72011-05-09 17:00:02 +00001112/**
1113 * Returns true if the rects edges are integer-aligned.
1114 */
1115static bool isIRect(const GrRect& r) {
1116 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1117 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1118}
1119
bsalomon@google.com205d4602011-04-25 12:43:45 +00001120static bool apply_aa_to_rect(GrDrawTarget* target,
1121 GrGpu* gpu,
1122 const GrPaint& paint,
1123 const GrRect& rect,
1124 GrScalar width,
1125 const GrMatrix* matrix,
1126 GrMatrix* combinedMatrix,
1127 GrRect* devRect) {
1128 // we use a simple alpha ramp to do aa on axis-aligned rects
1129 // do AA with alpha ramp if the caller requested AA, the rect
1130 // will be axis-aligned,the render target is not
1131 // multisampled, and the rect won't land on integer coords.
1132
1133 if (!paint.fAntiAlias) {
1134 return false;
1135 }
1136
1137 if (target->getRenderTarget()->isMultisampled()) {
1138 return false;
1139 }
1140
1141 if (0 == width && gpu->supportsAALines()) {
1142 return false;
1143 }
1144
1145 if (!target->getViewMatrix().preservesAxisAlignment()) {
1146 return false;
1147 }
1148
1149 if (NULL != matrix &&
1150 !matrix->preservesAxisAlignment()) {
1151 return false;
1152 }
1153
1154 *combinedMatrix = target->getViewMatrix();
1155 if (NULL != matrix) {
1156 combinedMatrix->preConcat(*matrix);
1157 GrAssert(combinedMatrix->preservesAxisAlignment());
1158 }
1159
1160 combinedMatrix->mapRect(devRect, rect);
1161 devRect->sort();
1162
1163 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001164 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001165 } else {
1166 return true;
1167 }
1168}
1169
bsalomon@google.com27847de2011-02-22 20:59:41 +00001170void GrContext::drawRect(const GrPaint& paint,
1171 const GrRect& rect,
1172 GrScalar width,
1173 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001174 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001175
1176 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001177 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001178
bsalomon@google.com205d4602011-04-25 12:43:45 +00001179 GrRect devRect = rect;
1180 GrMatrix combinedMatrix;
1181 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1182 &combinedMatrix, &devRect);
1183
1184 if (doAA) {
1185 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001186 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001187 GrMatrix inv;
1188 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001189 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001190 }
1191 }
1192 target->setViewMatrix(GrMatrix::I());
1193 if (width >= 0) {
1194 GrVec strokeSize;;
1195 if (width > 0) {
1196 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001197 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001198 strokeSize.setAbs(strokeSize);
1199 } else {
1200 strokeSize.set(GR_Scalar1, GR_Scalar1);
1201 }
1202 strokeAARect(target, paint, devRect, strokeSize);
1203 } else {
1204 fillAARect(target, paint, devRect);
1205 }
1206 return;
1207 }
1208
bsalomon@google.com27847de2011-02-22 20:59:41 +00001209 if (width >= 0) {
1210 // TODO: consider making static vertex buffers for these cases.
1211 // Hairline could be done by just adding closing vertex to
1212 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001213 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1214
bsalomon@google.com27847de2011-02-22 20:59:41 +00001215 static const int worstCaseVertCount = 10;
1216 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1217
1218 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001219 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001220 return;
1221 }
1222
1223 GrPrimitiveType primType;
1224 int vertCount;
1225 GrPoint* vertex = geo.positions();
1226
1227 if (width > 0) {
1228 vertCount = 10;
1229 primType = kTriangleStrip_PrimitiveType;
1230 setStrokeRectStrip(vertex, rect, width);
1231 } else {
1232 // hairline
1233 vertCount = 5;
1234 primType = kLineStrip_PrimitiveType;
1235 vertex[0].set(rect.fLeft, rect.fTop);
1236 vertex[1].set(rect.fRight, rect.fTop);
1237 vertex[2].set(rect.fRight, rect.fBottom);
1238 vertex[3].set(rect.fLeft, rect.fBottom);
1239 vertex[4].set(rect.fLeft, rect.fTop);
1240 }
1241
1242 GrDrawTarget::AutoViewMatrixRestore avmr;
1243 if (NULL != matrix) {
1244 avmr.set(target);
1245 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001246 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001247 }
1248
1249 target->drawNonIndexed(primType, 0, vertCount);
1250 } else {
1251 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001252 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001253 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1254 if (NULL == sqVB) {
1255 GrPrintf("Failed to create static rect vb.\n");
1256 return;
1257 }
1258 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001259 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1260 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001261 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001262 0, rect.height(), rect.fTop,
1263 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001264
1265 if (NULL != matrix) {
1266 m.postConcat(*matrix);
1267 }
1268
1269 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001270 target->preConcatSamplerMatrices(stageMask, m);
1271
bsalomon@google.com27847de2011-02-22 20:59:41 +00001272 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1273 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001274 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001275 #endif
1276 }
1277}
1278
1279void GrContext::drawRectToRect(const GrPaint& paint,
1280 const GrRect& dstRect,
1281 const GrRect& srcRect,
1282 const GrMatrix* dstMatrix,
1283 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001284 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001285
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001286 // srcRect refers to paint's first texture
1287 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001288 drawRect(paint, dstRect, -1, dstMatrix);
1289 return;
1290 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001291
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1293
1294#if GR_STATIC_RECT_VB
1295 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001296
1297 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1299
1300 GrMatrix m;
1301
1302 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1303 0, dstRect.height(), dstRect.fTop,
1304 0, 0, GrMatrix::I()[8]);
1305 if (NULL != dstMatrix) {
1306 m.postConcat(*dstMatrix);
1307 }
1308 target->preConcatViewMatrix(m);
1309
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001310 // srcRect refers to first stage
1311 int otherStageMask = paint.getActiveStageMask() &
1312 (~(1 << GrPaint::kFirstTextureStage));
1313 if (otherStageMask) {
1314 target->preConcatSamplerMatrices(otherStageMask, m);
1315 }
1316
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1318 0, srcRect.height(), srcRect.fTop,
1319 0, 0, GrMatrix::I()[8]);
1320 if (NULL != srcMatrix) {
1321 m.postConcat(*srcMatrix);
1322 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001323 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001325 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1326 if (NULL == sqVB) {
1327 GrPrintf("Failed to create static rect vb.\n");
1328 return;
1329 }
1330 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1332#else
1333
1334 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001335#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001336 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001337#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001338 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1339#endif
1340
1341 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1342 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1343 srcRects[0] = &srcRect;
1344 srcMatrices[0] = srcMatrix;
1345
1346 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1347#endif
1348}
1349
1350void GrContext::drawVertices(const GrPaint& paint,
1351 GrPrimitiveType primitiveType,
1352 int vertexCount,
1353 const GrPoint positions[],
1354 const GrPoint texCoords[],
1355 const GrColor colors[],
1356 const uint16_t indices[],
1357 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001358 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001359
1360 GrDrawTarget::AutoReleaseGeometry geo;
1361
1362 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1363
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001364 bool hasTexCoords[GrPaint::kTotalStages] = {
1365 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1366 0 // remaining stages use positions
1367 };
1368
1369 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001370
1371 if (NULL != colors) {
1372 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001373 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001374 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001375
1376 if (sizeof(GrPoint) != vertexSize) {
1377 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001378 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379 return;
1380 }
1381 int texOffsets[GrDrawTarget::kMaxTexCoords];
1382 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001383 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1384 texOffsets,
1385 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001386 void* curVertex = geo.vertices();
1387
1388 for (int i = 0; i < vertexCount; ++i) {
1389 *((GrPoint*)curVertex) = positions[i];
1390
1391 if (texOffsets[0] > 0) {
1392 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1393 }
1394 if (colorOffset > 0) {
1395 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1396 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001397 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398 }
1399 } else {
1400 target->setVertexSourceToArray(layout, positions, vertexCount);
1401 }
1402
bsalomon@google.com91958362011-06-13 17:58:13 +00001403 // we don't currently apply offscreen AA to this path. Need improved
1404 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001405
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001406 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001407 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001408 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001409 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001410 target->drawNonIndexed(primitiveType, 0, vertexCount);
1411 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001412}
1413
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001414///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415
reed@google.com07f3ee12011-05-16 17:21:57 +00001416void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1417 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001418
bsalomon@google.com27847de2011-02-22 20:59:41 +00001419 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001420 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1421 if (NULL == pr) {
1422 GrPrintf("Unable to find path renderer compatible with path.\n");
1423 return;
1424 }
1425
bsalomon@google.comee435122011-07-01 14:57:55 +00001426 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1427 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001428
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001429 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001430 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001431
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001432 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001433
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001434 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001435 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1436 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001437 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001438 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001439 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001440 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001441 return;
1442 }
1443 }
reed@google.com70c136e2011-06-03 19:51:26 +00001444
reed@google.com07f3ee12011-05-16 17:21:57 +00001445 GrRect pathBounds = path.getBounds();
1446 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001447 if (NULL != translate) {
1448 pathBounds.offset(*translate);
1449 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001450 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001451 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001452 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001453 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001454 return;
1455 }
1456 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001457 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001458 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1459 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001460 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1461 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1462 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001463 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001464 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1465 }
1466 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001467 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001468 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001469 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1470 GrRect rect;
1471 if (clipIBounds.fTop < bound.fTop) {
1472 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1473 clipIBounds.fRight, bound.fTop);
1474 target->drawSimpleRect(rect, NULL, stageMask);
1475 }
1476 if (clipIBounds.fLeft < bound.fLeft) {
1477 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1478 bound.fLeft, bound.fBottom);
1479 target->drawSimpleRect(rect, NULL, stageMask);
1480 }
1481 if (clipIBounds.fRight > bound.fRight) {
1482 rect.setLTRB(bound.fRight, bound.fTop,
1483 clipIBounds.fRight, bound.fBottom);
1484 target->drawSimpleRect(rect, NULL, stageMask);
1485 }
1486 if (clipIBounds.fBottom > bound.fBottom) {
1487 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1488 clipIBounds.fRight, clipIBounds.fBottom);
1489 target->drawSimpleRect(rect, NULL, stageMask);
1490 }
1491 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001492 return;
1493 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001494 }
1495 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001496}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001497
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498////////////////////////////////////////////////////////////////////////////////
1499
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001500void GrContext::flush(int flagsBitfield) {
1501 if (kDiscard_FlushBit & flagsBitfield) {
1502 fDrawBuffer->reset();
1503 } else {
1504 flushDrawBuffer();
1505 }
1506
1507 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001508 fGpu->forceRenderTargetFlush();
1509 }
1510}
1511
1512void GrContext::flushText() {
1513 if (kText_DrawCategory == fLastDrawCategory) {
1514 flushDrawBuffer();
1515 }
1516}
1517
1518void GrContext::flushDrawBuffer() {
1519#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001520 if (fDrawBuffer) {
1521 fDrawBuffer->playback(fGpu);
1522 fDrawBuffer->reset();
1523 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001524#endif
1525}
1526
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001527bool GrContext::readTexturePixels(GrTexture* texture,
1528 int left, int top, int width, int height,
1529 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001530 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001531
1532 // TODO: code read pixels for textures that aren't rendertargets
1533
1534 this->flush();
1535 GrRenderTarget* target = texture->asRenderTarget();
1536 if (NULL != target) {
1537 return fGpu->readPixels(target,
1538 left, top, width, height,
1539 config, buffer);
1540 } else {
1541 return false;
1542 }
1543}
1544
1545bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1546 int left, int top, int width, int height,
1547 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001548 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001549 uint32_t flushFlags = 0;
1550 if (NULL == target) {
1551 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1552 }
1553
1554 this->flush(flushFlags);
1555 return fGpu->readPixels(target,
1556 left, top, width, height,
1557 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001558}
1559
1560void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001561 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001562 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001563 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001564
1565 // TODO: when underlying api has a direct way to do this we should use it
1566 // (e.g. glDrawPixels on desktop GL).
1567
bsalomon@google.com5c638652011-07-18 19:31:59 +00001568 this->flush(true);
1569
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001570 const GrTextureDesc desc = {
1571 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001572 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001573 GrAutoScratchTexture ast(this, desc);
1574 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001575 if (NULL == texture) {
1576 return;
1577 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001578 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001579
bsalomon@google.com27847de2011-02-22 20:59:41 +00001580 GrDrawTarget::AutoStateRestore asr(fGpu);
1581
1582 GrMatrix matrix;
1583 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1584 fGpu->setViewMatrix(matrix);
1585
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001586 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001587 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1588 fGpu->setAlpha(0xFF);
1589 fGpu->setBlendFunc(kOne_BlendCoeff,
1590 kZero_BlendCoeff);
1591 fGpu->setTexture(0, texture);
1592
1593 GrSamplerState sampler;
1594 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001595 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001596 sampler.setMatrix(matrix);
1597 fGpu->setSamplerState(0, sampler);
1598
1599 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1600 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001601 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001602 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1603 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001604 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001605 return;
1606 }
1607 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1608 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1609}
1610////////////////////////////////////////////////////////////////////////////////
1611
1612void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001613
1614 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1615 int s = i + GrPaint::kFirstTextureStage;
1616 target->setTexture(s, paint.getTexture(i));
1617 target->setSamplerState(s, *paint.getTextureSampler(i));
1618 }
1619
1620 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1621
1622 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1623 int s = i + GrPaint::kFirstMaskStage;
1624 target->setTexture(s, paint.getMask(i));
1625 target->setSamplerState(s, *paint.getMaskSampler(i));
1626 }
1627
bsalomon@google.com27847de2011-02-22 20:59:41 +00001628 target->setColor(paint.fColor);
1629
1630 if (paint.fDither) {
1631 target->enableState(GrDrawTarget::kDither_StateBit);
1632 } else {
1633 target->disableState(GrDrawTarget::kDither_StateBit);
1634 }
1635 if (paint.fAntiAlias) {
1636 target->enableState(GrDrawTarget::kAntialias_StateBit);
1637 } else {
1638 target->disableState(GrDrawTarget::kAntialias_StateBit);
1639 }
1640 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001641 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001642}
1643
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001644GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001645 DrawCategory category) {
1646 if (category != fLastDrawCategory) {
1647 flushDrawBuffer();
1648 fLastDrawCategory = category;
1649 }
1650 SetPaint(paint, fGpu);
1651 GrDrawTarget* target = fGpu;
1652 switch (category) {
1653 case kText_DrawCategory:
1654#if DEFER_TEXT_RENDERING
1655 target = fDrawBuffer;
1656 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1657#else
1658 target = fGpu;
1659#endif
1660 break;
1661 case kUnbuffered_DrawCategory:
1662 target = fGpu;
1663 break;
1664 case kBuffered_DrawCategory:
1665 target = fDrawBuffer;
1666 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1667 break;
1668 }
1669 return target;
1670}
1671
bsalomon@google.com30085192011-08-19 15:42:31 +00001672GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1673 const GrPath& path,
1674 GrPathFill fill) {
1675 if (NULL == fPathRendererChain) {
1676 fPathRendererChain =
1677 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1678 }
1679 return fPathRendererChain->getPathRenderer(target, path, fill);
1680}
1681
bsalomon@google.com27847de2011-02-22 20:59:41 +00001682////////////////////////////////////////////////////////////////////////////////
1683
bsalomon@google.com27847de2011-02-22 20:59:41 +00001684void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001685 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001686 fGpu->setRenderTarget(target);
1687}
1688
1689GrRenderTarget* GrContext::getRenderTarget() {
1690 return fGpu->getRenderTarget();
1691}
1692
1693const GrRenderTarget* GrContext::getRenderTarget() const {
1694 return fGpu->getRenderTarget();
1695}
1696
1697const GrMatrix& GrContext::getMatrix() const {
1698 return fGpu->getViewMatrix();
1699}
1700
1701void GrContext::setMatrix(const GrMatrix& m) {
1702 fGpu->setViewMatrix(m);
1703}
1704
1705void GrContext::concatMatrix(const GrMatrix& m) const {
1706 fGpu->preConcatViewMatrix(m);
1707}
1708
1709static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1710 intptr_t mask = 1 << shift;
1711 if (pred) {
1712 bits |= mask;
1713 } else {
1714 bits &= ~mask;
1715 }
1716 return bits;
1717}
1718
1719void GrContext::resetStats() {
1720 fGpu->resetStats();
1721}
1722
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001723const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001724 return fGpu->getStats();
1725}
1726
1727void GrContext::printStats() const {
1728 fGpu->printStats();
1729}
1730
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001731GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001732 fGpu = gpu;
1733 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001734 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001735
bsalomon@google.com30085192011-08-19 15:42:31 +00001736 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001737
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001738 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1739 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001740 fFontCache = new GrFontCache(fGpu);
1741
1742 fLastDrawCategory = kUnbuffered_DrawCategory;
1743
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001744 fDrawBuffer = NULL;
1745 fDrawBufferVBAllocPool = NULL;
1746 fDrawBufferIBAllocPool = NULL;
1747
bsalomon@google.com205d4602011-04-25 12:43:45 +00001748 fAAFillRectIndexBuffer = NULL;
1749 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001750
1751 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1752 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1753 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1754 }
1755 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001756
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001757 this->setupDrawBuffer();
1758}
1759
1760void GrContext::setupDrawBuffer() {
1761
1762 GrAssert(NULL == fDrawBuffer);
1763 GrAssert(NULL == fDrawBufferVBAllocPool);
1764 GrAssert(NULL == fDrawBufferIBAllocPool);
1765
bsalomon@google.com27847de2011-02-22 20:59:41 +00001766#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001767 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001768 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001769 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1770 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001771 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001772 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001773 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001774 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1775
1776 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1777 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001778#endif
1779
1780#if BATCH_RECT_TO_RECT
1781 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1782#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001783}
1784
bsalomon@google.com27847de2011-02-22 20:59:41 +00001785GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1786 GrDrawTarget* target;
1787#if DEFER_TEXT_RENDERING
1788 target = prepareToDraw(paint, kText_DrawCategory);
1789#else
1790 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1791#endif
1792 SetPaint(paint, target);
1793 return target;
1794}
1795
1796const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1797 return fGpu->getQuadIndexBuffer();
1798}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001799
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001800void GrContext::convolveInX(GrTexture* texture,
1801 const SkRect& rect,
1802 const float* kernel,
1803 int kernelWidth) {
1804 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1805 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1806}
1807
1808void GrContext::convolveInY(GrTexture* texture,
1809 const SkRect& rect,
1810 const float* kernel,
1811 int kernelWidth) {
1812 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1813 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1814}
1815
1816void GrContext::convolve(GrTexture* texture,
1817 const SkRect& rect,
1818 float imageIncrement[2],
1819 const float* kernel,
1820 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001821 GrDrawTarget::AutoStateRestore asr(fGpu);
1822 GrMatrix sampleM;
1823 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1824 GrSamplerState::kClamp_WrapMode,
1825 GrSamplerState::kConvolution_Filter);
1826 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001827 sampleM.setScale(GR_Scalar1 / texture->width(),
1828 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001829 sampler.setMatrix(sampleM);
1830 fGpu->setSamplerState(0, sampler);
1831 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001832 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001833 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001834 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1835}