blob: 639e25d68535f1bc04adb3a4dae6cadc1bcb105b [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) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000525 return NULL;
526 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000527 if (desc.fSampleCnt &&
528 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000529 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000530 }
531 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
532 desc.fSampleCnt &&
533 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
534 return NULL;
535 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000536 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000537}
538
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000539///////////////////////////////////////////////////////////////////////////////
540
bsalomon@google.com27847de2011-02-22 20:59:41 +0000541bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000542 int width, int height) const {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000543 if (!fGpu->supports8BitPalette()) {
544 return false;
545 }
546
547
548 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
549
550 if (!isPow2) {
551 if (!fGpu->npotTextureSupport()) {
552 return false;
553 }
554
555 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
556 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
557 if (tiled && !fGpu->npotTextureTileSupport()) {
558 return false;
559 }
560 }
561 return true;
562}
563
564////////////////////////////////////////////////////////////////////////////////
565
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000566const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
567
bsalomon@google.com27847de2011-02-22 20:59:41 +0000568void GrContext::setClip(const GrClip& clip) {
569 fGpu->setClip(clip);
570 fGpu->enableState(GrDrawTarget::kClip_StateBit);
571}
572
573void GrContext::setClip(const GrIRect& rect) {
574 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000575 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000576 fGpu->setClip(clip);
577}
578
579////////////////////////////////////////////////////////////////////////////////
580
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000581void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000582 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000583 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000584}
585
586void GrContext::drawPaint(const GrPaint& paint) {
587 // set rect to be big enough to fill the space, but not super-huge, so we
588 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000589 GrRect r;
590 r.setLTRB(0, 0,
591 GrIntToScalar(getRenderTarget()->width()),
592 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000593 GrMatrix inverse;
594 if (fGpu->getViewInverse(&inverse)) {
595 inverse.mapRect(&r);
596 } else {
597 GrPrintf("---- fGpu->getViewInverse failed\n");
598 }
599 this->drawRect(paint, r);
600}
601
bsalomon@google.com205d4602011-04-25 12:43:45 +0000602////////////////////////////////////////////////////////////////////////////////
603
bsalomon@google.com91958362011-06-13 17:58:13 +0000604struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000605 enum Downsample {
606 k4x4TwoPass_Downsample,
607 k4x4SinglePass_Downsample,
608 kFSAA_Downsample
609 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000610 int fTileSizeX;
611 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000612 int fTileCountX;
613 int fTileCountY;
614 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000615 GrAutoScratchTexture fOffscreen0;
616 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000617 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000618 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000619};
620
bsalomon@google.com471d4712011-08-23 15:45:25 +0000621bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000622 const GrPaint& paint,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000623 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000624#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000625 return false;
626#else
627 if (!paint.fAntiAlias) {
628 return false;
629 }
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000630 // Line primitves are always rasterized as 1 pixel wide.
631 // Super-sampling would make them too thin but MSAA would be OK.
632 if (isHairLines &&
633 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA())) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000634 return false;
635 }
636 if (target->getRenderTarget()->isMultisampled()) {
637 return false;
638 }
639 // we have to be sure that the blend equation is expressible
640 // as simple src / dst coeffecients when the source
641 // is already modulated by the coverage fraction.
642 // We could use dual-source blending to get the correct per-pixel
643 // dst coeffecient for the remaining cases.
644 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
645 kOne_BlendCoeff != paint.fDstBlendCoeff &&
646 kISA_BlendCoeff != paint.fDstBlendCoeff) {
647 return false;
648 }
649 return true;
650#endif
651}
652
bsalomon@google.com91958362011-06-13 17:58:13 +0000653bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000654 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000655 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000656 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000657 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000658
659 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000660
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000661 GrAssert(NULL == record->fOffscreen0.texture());
662 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000663 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000664
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000665 int boundW = boundRect.width();
666 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000667
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000668 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000669
670 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
671 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
672
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000673 if (requireStencil) {
674 desc.fFlags = kRenderTarget_GrTextureFlagBit;
675 } else {
676 desc.fFlags = kRenderTarget_GrTextureFlagBit |
677 kNoStencil_GrTextureFlagBit;
678 }
679
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000680 desc.fFormat = kRGBA_8888_GrPixelConfig;
681
bsalomon@google.com91958362011-06-13 17:58:13 +0000682 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000683 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000684 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000685 desc.fAALevel = kMed_GrAALevel;
686 } else {
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000687 record->fDownsample = (fGpu->supportsShaders()) ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000688 OffscreenRecord::k4x4SinglePass_Downsample :
689 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000690 record->fScale = OFFSCREEN_SSAA_SCALE;
691 // both downsample paths assume this
692 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000693 desc.fAALevel = kNone_GrAALevel;
694 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000695 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
696 // of simple circles?
697 if (pr) {
698 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
699 }
700
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000701 desc.fWidth *= record->fScale;
702 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000703 record->fOffscreen0.set(this, desc);
704 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000705 return false;
706 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000707 // the approximate lookup might have given us some slop space, might as well
708 // use it when computing the tiles size.
709 // these are scale values, will adjust after considering
710 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000711 record->fTileSizeX = record->fOffscreen0.texture()->width();
712 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000713
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000714 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000715 desc.fWidth /= 2;
716 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000717 record->fOffscreen1.set(this, desc);
718 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000719 return false;
720 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000721 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000722 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000723 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000724 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000725 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000726 record->fTileSizeX /= record->fScale;
727 record->fTileSizeY /= record->fScale;
728
729 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
730 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
731
tomhudson@google.com237a4612011-07-19 15:44:00 +0000732 record->fClip = target->getClip();
733
bsalomon@google.com91958362011-06-13 17:58:13 +0000734 target->saveCurrentDrawState(&record->fSavedState);
735 return true;
736}
737
738void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
739 const GrIRect& boundRect,
740 int tileX, int tileY,
741 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000742
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000743 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000744 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000745
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000746 GrPaint tempPaint;
747 tempPaint.reset();
748 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000749 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000750
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000751 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000752 int left = boundRect.fLeft + tileX * record->fTileSizeX;
753 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000754 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000755 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000756 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000757 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000758 target->postConcatViewMatrix(scaleM);
759
bsalomon@google.com91958362011-06-13 17:58:13 +0000760 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000761 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000762 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000763 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000764 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
765 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000766 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000767#if 0
768 // visualize tile boundaries by setting edges of offscreen to white
769 // and interior to tranparent. black.
770 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000771
bsalomon@google.com91958362011-06-13 17:58:13 +0000772 static const int gOffset = 2;
773 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
774 record->fScale * w - gOffset,
775 record->fScale * h - gOffset);
776 target->clear(&clear2, 0x0);
777#else
778 target->clear(&clear, 0x0);
779#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000780}
781
bsalomon@google.com91958362011-06-13 17:58:13 +0000782void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000783 const GrPaint& paint,
784 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000785 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000786 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000787 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000788 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000789 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000790 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000791 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
792 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000793 tileRect.fRight = (tileX == record->fTileCountX-1) ?
794 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000795 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000796 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
797 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000798 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000799
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000800 GrSamplerState::Filter filter;
801 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
802 filter = GrSamplerState::k4x4Downsample_Filter;
803 } else {
804 filter = GrSamplerState::kBilinear_Filter;
805 }
806
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000807 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000808 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000809 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000810
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000811 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000812 int scale;
813
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000814 enum {
815 kOffscreenStage = GrPaint::kTotalStages,
816 };
817
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000818 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000819 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000820 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000821 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000822
823 // Do 2x2 downsample from first to second
824 target->setTexture(kOffscreenStage, src);
825 target->setRenderTarget(dst);
826 target->setViewMatrix(GrMatrix::I());
827 sampleM.setScale(scale * GR_Scalar1 / src->width(),
828 scale * GR_Scalar1 / src->height());
829 sampler.setMatrix(sampleM);
830 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000831 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
832 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000833 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
834
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000835 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000836 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000837 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000838 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000839 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000840 } else {
841 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
842 record->fDownsample);
843 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000844 }
845
bsalomon@google.com91958362011-06-13 17:58:13 +0000846 // setup for draw back to main RT, we use the original
847 // draw state setup by the caller plus an additional coverage
848 // stage to handle the AA resolve. Also, we use an identity
849 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000850 int stageMask = paint.getActiveStageMask();
851
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000852 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000853 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000854
855 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000856 GrMatrix invVM;
857 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000858 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000859 }
860 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000861 // This is important when tiling, otherwise second tile's
862 // pass 1 view matrix will be incorrect.
863 GrDrawTarget::AutoViewMatrixRestore avmr(target);
864
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000865 target->setViewMatrix(GrMatrix::I());
866
867 target->setTexture(kOffscreenStage, src);
868 sampleM.setScale(scale * GR_Scalar1 / src->width(),
869 scale * GR_Scalar1 / src->height());
870 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000871 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000873 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000874
reed@google.com20efde72011-05-09 17:00:02 +0000875 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000876 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000877 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000878 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000879}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000880
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000881void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
882 GrPathRenderer* pr,
883 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000884 if (pr) {
885 // Counterpart of scale() in prepareForOffscreenAA()
886 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
887 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000888 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000889}
890
891////////////////////////////////////////////////////////////////////////////////
892
bsalomon@google.com27847de2011-02-22 20:59:41 +0000893/* create a triangle strip that strokes the specified triangle. There are 8
894 unique vertices, but we repreat the last 2 to close up. Alternatively we
895 could use an indices array, and then only send 8 verts, but not sure that
896 would be faster.
897 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000898static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000899 GrScalar width) {
900 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000901 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000902
903 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
904 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
905 verts[2].set(rect.fRight - rad, rect.fTop + rad);
906 verts[3].set(rect.fRight + rad, rect.fTop - rad);
907 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
908 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
909 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
910 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
911 verts[8] = verts[0];
912 verts[9] = verts[1];
913}
914
bsalomon@google.com205d4602011-04-25 12:43:45 +0000915static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000916 // FIXME: This was copied from SkGpuDevice, seems like
917 // we should have already smeared a in caller if that
918 // is what is desired.
919 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000920 unsigned a = GrColorUnpackA(paint.fColor);
921 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000922 } else {
923 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000924 }
925}
926
927static void setInsetFan(GrPoint* pts, size_t stride,
928 const GrRect& r, GrScalar dx, GrScalar dy) {
929 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
930}
931
932static const uint16_t gFillAARectIdx[] = {
933 0, 1, 5, 5, 4, 0,
934 1, 2, 6, 6, 5, 1,
935 2, 3, 7, 7, 6, 2,
936 3, 0, 4, 4, 7, 3,
937 4, 5, 6, 6, 7, 4,
938};
939
940int GrContext::aaFillRectIndexCount() const {
941 return GR_ARRAY_COUNT(gFillAARectIdx);
942}
943
944GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
945 if (NULL == fAAFillRectIndexBuffer) {
946 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
947 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000948 if (NULL != fAAFillRectIndexBuffer) {
949 #if GR_DEBUG
950 bool updated =
951 #endif
952 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
953 sizeof(gFillAARectIdx));
954 GR_DEBUGASSERT(updated);
955 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000956 }
957 return fAAFillRectIndexBuffer;
958}
959
960static const uint16_t gStrokeAARectIdx[] = {
961 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
962 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
963 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
964 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
965
966 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
967 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
968 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
969 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
970
971 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
972 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
973 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
974 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
975};
976
977int GrContext::aaStrokeRectIndexCount() const {
978 return GR_ARRAY_COUNT(gStrokeAARectIdx);
979}
980
981GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
982 if (NULL == fAAStrokeRectIndexBuffer) {
983 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
984 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000985 if (NULL != fAAStrokeRectIndexBuffer) {
986 #if GR_DEBUG
987 bool updated =
988 #endif
989 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
990 sizeof(gStrokeAARectIdx));
991 GR_DEBUGASSERT(updated);
992 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000993 }
994 return fAAStrokeRectIndexBuffer;
995}
996
997void GrContext::fillAARect(GrDrawTarget* target,
998 const GrPaint& paint,
999 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001000 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1001 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001002
1003 size_t vsize = GrDrawTarget::VertexSize(layout);
1004
1005 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001006 if (!geo.succeeded()) {
1007 GrPrintf("Failed to get space for vertices!\n");
1008 return;
1009 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001010 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1011 if (NULL == indexBuffer) {
1012 GrPrintf("Failed to create index buffer!\n");
1013 return;
1014 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001015
1016 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1017
1018 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1019 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1020
1021 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1022 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1023
1024 verts += sizeof(GrPoint);
1025 for (int i = 0; i < 4; ++i) {
1026 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1027 }
1028
1029 GrColor innerColor = getColorForMesh(paint);
1030 verts += 4 * vsize;
1031 for (int i = 0; i < 4; ++i) {
1032 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1033 }
1034
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001035 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001036
1037 target->drawIndexed(kTriangles_PrimitiveType, 0,
1038 0, 8, this->aaFillRectIndexCount());
1039}
1040
1041void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1042 const GrRect& devRect, const GrVec& devStrokeSize) {
1043 const GrScalar& dx = devStrokeSize.fX;
1044 const GrScalar& dy = devStrokeSize.fY;
1045 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1046 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1047
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001048 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1049 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001050
1051 GrScalar spare;
1052 {
1053 GrScalar w = devRect.width() - dx;
1054 GrScalar h = devRect.height() - dy;
1055 spare = GrMin(w, h);
1056 }
1057
1058 if (spare <= 0) {
1059 GrRect r(devRect);
1060 r.inset(-rx, -ry);
1061 fillAARect(target, paint, r);
1062 return;
1063 }
1064
1065 size_t vsize = GrDrawTarget::VertexSize(layout);
1066
1067 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001068 if (!geo.succeeded()) {
1069 GrPrintf("Failed to get space for vertices!\n");
1070 return;
1071 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001072 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1073 if (NULL == indexBuffer) {
1074 GrPrintf("Failed to create index buffer!\n");
1075 return;
1076 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001077
1078 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1079
1080 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1081 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1082 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1083 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1084
1085 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1086 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1087 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1088 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1089
1090 verts += sizeof(GrPoint);
1091 for (int i = 0; i < 4; ++i) {
1092 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1093 }
1094
1095 GrColor innerColor = getColorForMesh(paint);
1096 verts += 4 * vsize;
1097 for (int i = 0; i < 8; ++i) {
1098 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1099 }
1100
1101 verts += 8 * vsize;
1102 for (int i = 0; i < 8; ++i) {
1103 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1104 }
1105
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001106 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001107 target->drawIndexed(kTriangles_PrimitiveType,
1108 0, 0, 16, aaStrokeRectIndexCount());
1109}
1110
reed@google.com20efde72011-05-09 17:00:02 +00001111/**
1112 * Returns true if the rects edges are integer-aligned.
1113 */
1114static bool isIRect(const GrRect& r) {
1115 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1116 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1117}
1118
bsalomon@google.com205d4602011-04-25 12:43:45 +00001119static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001120 const GrPaint& paint,
1121 const GrRect& rect,
1122 GrScalar width,
1123 const GrMatrix* matrix,
1124 GrMatrix* combinedMatrix,
1125 GrRect* devRect) {
1126 // we use a simple alpha ramp to do aa on axis-aligned rects
1127 // do AA with alpha ramp if the caller requested AA, the rect
1128 // will be axis-aligned,the render target is not
1129 // multisampled, and the rect won't land on integer coords.
1130
1131 if (!paint.fAntiAlias) {
1132 return false;
1133 }
1134
1135 if (target->getRenderTarget()->isMultisampled()) {
1136 return false;
1137 }
1138
bsalomon@google.com471d4712011-08-23 15:45:25 +00001139 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001140 return false;
1141 }
1142
1143 if (!target->getViewMatrix().preservesAxisAlignment()) {
1144 return false;
1145 }
1146
1147 if (NULL != matrix &&
1148 !matrix->preservesAxisAlignment()) {
1149 return false;
1150 }
1151
1152 *combinedMatrix = target->getViewMatrix();
1153 if (NULL != matrix) {
1154 combinedMatrix->preConcat(*matrix);
1155 GrAssert(combinedMatrix->preservesAxisAlignment());
1156 }
1157
1158 combinedMatrix->mapRect(devRect, rect);
1159 devRect->sort();
1160
1161 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001162 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001163 } else {
1164 return true;
1165 }
1166}
1167
bsalomon@google.com27847de2011-02-22 20:59:41 +00001168void GrContext::drawRect(const GrPaint& paint,
1169 const GrRect& rect,
1170 GrScalar width,
1171 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001172 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001173
1174 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001175 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001176
bsalomon@google.com205d4602011-04-25 12:43:45 +00001177 GrRect devRect = rect;
1178 GrMatrix combinedMatrix;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001179 bool doAA = apply_aa_to_rect(target, paint, rect, width, matrix,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001180 &combinedMatrix, &devRect);
1181
1182 if (doAA) {
1183 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001184 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001185 GrMatrix inv;
1186 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001187 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001188 }
1189 }
1190 target->setViewMatrix(GrMatrix::I());
1191 if (width >= 0) {
1192 GrVec strokeSize;;
1193 if (width > 0) {
1194 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001195 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001196 strokeSize.setAbs(strokeSize);
1197 } else {
1198 strokeSize.set(GR_Scalar1, GR_Scalar1);
1199 }
1200 strokeAARect(target, paint, devRect, strokeSize);
1201 } else {
1202 fillAARect(target, paint, devRect);
1203 }
1204 return;
1205 }
1206
bsalomon@google.com27847de2011-02-22 20:59:41 +00001207 if (width >= 0) {
1208 // TODO: consider making static vertex buffers for these cases.
1209 // Hairline could be done by just adding closing vertex to
1210 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001211 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1212
bsalomon@google.com27847de2011-02-22 20:59:41 +00001213 static const int worstCaseVertCount = 10;
1214 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1215
1216 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001217 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001218 return;
1219 }
1220
1221 GrPrimitiveType primType;
1222 int vertCount;
1223 GrPoint* vertex = geo.positions();
1224
1225 if (width > 0) {
1226 vertCount = 10;
1227 primType = kTriangleStrip_PrimitiveType;
1228 setStrokeRectStrip(vertex, rect, width);
1229 } else {
1230 // hairline
1231 vertCount = 5;
1232 primType = kLineStrip_PrimitiveType;
1233 vertex[0].set(rect.fLeft, rect.fTop);
1234 vertex[1].set(rect.fRight, rect.fTop);
1235 vertex[2].set(rect.fRight, rect.fBottom);
1236 vertex[3].set(rect.fLeft, rect.fBottom);
1237 vertex[4].set(rect.fLeft, rect.fTop);
1238 }
1239
1240 GrDrawTarget::AutoViewMatrixRestore avmr;
1241 if (NULL != matrix) {
1242 avmr.set(target);
1243 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001244 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001245 }
1246
1247 target->drawNonIndexed(primType, 0, vertCount);
1248 } else {
1249 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001250 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001251 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1252 if (NULL == sqVB) {
1253 GrPrintf("Failed to create static rect vb.\n");
1254 return;
1255 }
1256 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001257 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1258 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001259 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001260 0, rect.height(), rect.fTop,
1261 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001262
1263 if (NULL != matrix) {
1264 m.postConcat(*matrix);
1265 }
1266
1267 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001268 target->preConcatSamplerMatrices(stageMask, m);
1269
bsalomon@google.com27847de2011-02-22 20:59:41 +00001270 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1271 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001272 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001273 #endif
1274 }
1275}
1276
1277void GrContext::drawRectToRect(const GrPaint& paint,
1278 const GrRect& dstRect,
1279 const GrRect& srcRect,
1280 const GrMatrix* dstMatrix,
1281 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001282 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001283
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001284 // srcRect refers to paint's first texture
1285 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001286 drawRect(paint, dstRect, -1, dstMatrix);
1287 return;
1288 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001289
bsalomon@google.com27847de2011-02-22 20:59:41 +00001290 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1291
1292#if GR_STATIC_RECT_VB
1293 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001294
1295 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001296 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1297
1298 GrMatrix m;
1299
1300 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1301 0, dstRect.height(), dstRect.fTop,
1302 0, 0, GrMatrix::I()[8]);
1303 if (NULL != dstMatrix) {
1304 m.postConcat(*dstMatrix);
1305 }
1306 target->preConcatViewMatrix(m);
1307
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001308 // srcRect refers to first stage
1309 int otherStageMask = paint.getActiveStageMask() &
1310 (~(1 << GrPaint::kFirstTextureStage));
1311 if (otherStageMask) {
1312 target->preConcatSamplerMatrices(otherStageMask, m);
1313 }
1314
bsalomon@google.com27847de2011-02-22 20:59:41 +00001315 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1316 0, srcRect.height(), srcRect.fTop,
1317 0, 0, GrMatrix::I()[8]);
1318 if (NULL != srcMatrix) {
1319 m.postConcat(*srcMatrix);
1320 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001321 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001322
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001323 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1324 if (NULL == sqVB) {
1325 GrPrintf("Failed to create static rect vb.\n");
1326 return;
1327 }
1328 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001329 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1330#else
1331
1332 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001333#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001334 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001335#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001336 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1337#endif
1338
1339 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1340 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1341 srcRects[0] = &srcRect;
1342 srcMatrices[0] = srcMatrix;
1343
1344 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1345#endif
1346}
1347
1348void GrContext::drawVertices(const GrPaint& paint,
1349 GrPrimitiveType primitiveType,
1350 int vertexCount,
1351 const GrPoint positions[],
1352 const GrPoint texCoords[],
1353 const GrColor colors[],
1354 const uint16_t indices[],
1355 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001356 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001357
1358 GrDrawTarget::AutoReleaseGeometry geo;
1359
1360 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1361
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001362 bool hasTexCoords[GrPaint::kTotalStages] = {
1363 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1364 0 // remaining stages use positions
1365 };
1366
1367 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001368
1369 if (NULL != colors) {
1370 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001371 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001372 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001373
1374 if (sizeof(GrPoint) != vertexSize) {
1375 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001376 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377 return;
1378 }
1379 int texOffsets[GrDrawTarget::kMaxTexCoords];
1380 int colorOffset;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001381 int edgeOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001382 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1383 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001384 &colorOffset,
1385 &edgeOffset);
1386 GrAssert(-1 == edgeOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001387 void* curVertex = geo.vertices();
1388
1389 for (int i = 0; i < vertexCount; ++i) {
1390 *((GrPoint*)curVertex) = positions[i];
1391
1392 if (texOffsets[0] > 0) {
1393 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1394 }
1395 if (colorOffset > 0) {
1396 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1397 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001398 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001399 }
1400 } else {
1401 target->setVertexSourceToArray(layout, positions, vertexCount);
1402 }
1403
bsalomon@google.com91958362011-06-13 17:58:13 +00001404 // we don't currently apply offscreen AA to this path. Need improved
1405 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001406
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001407 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001408 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001409 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001411 target->drawNonIndexed(primitiveType, 0, vertexCount);
1412 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001413}
1414
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001415///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416
reed@google.com07f3ee12011-05-16 17:21:57 +00001417void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1418 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001419
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001421 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1422 if (NULL == pr) {
1423 GrPrintf("Unable to find path renderer compatible with path.\n");
1424 return;
1425 }
1426
bsalomon@google.comee435122011-07-01 14:57:55 +00001427 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1428 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001429
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001430 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001431 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001432
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001433 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001434
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001435 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001436 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1437 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001438 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001439 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001440 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001441 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001442 return;
1443 }
1444 }
reed@google.com70c136e2011-06-03 19:51:26 +00001445
reed@google.com07f3ee12011-05-16 17:21:57 +00001446 GrRect pathBounds = path.getBounds();
1447 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001448 if (NULL != translate) {
1449 pathBounds.offset(*translate);
1450 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001451 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001452 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001453 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001454 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001455 return;
1456 }
1457 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001458 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001459 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1460 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001461 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1462 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1463 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001464 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001465 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1466 }
1467 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001468 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001469 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001470 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1471 GrRect rect;
1472 if (clipIBounds.fTop < bound.fTop) {
1473 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1474 clipIBounds.fRight, bound.fTop);
1475 target->drawSimpleRect(rect, NULL, stageMask);
1476 }
1477 if (clipIBounds.fLeft < bound.fLeft) {
1478 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1479 bound.fLeft, bound.fBottom);
1480 target->drawSimpleRect(rect, NULL, stageMask);
1481 }
1482 if (clipIBounds.fRight > bound.fRight) {
1483 rect.setLTRB(bound.fRight, bound.fTop,
1484 clipIBounds.fRight, bound.fBottom);
1485 target->drawSimpleRect(rect, NULL, stageMask);
1486 }
1487 if (clipIBounds.fBottom > bound.fBottom) {
1488 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1489 clipIBounds.fRight, clipIBounds.fBottom);
1490 target->drawSimpleRect(rect, NULL, stageMask);
1491 }
1492 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001493 return;
1494 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001495 }
1496 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001497}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001498
bsalomon@google.com27847de2011-02-22 20:59:41 +00001499////////////////////////////////////////////////////////////////////////////////
1500
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001501bool GrContext::supportsShaders() const {
1502 return fGpu->supportsShaders();
1503}
1504
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001505void GrContext::flush(int flagsBitfield) {
1506 if (kDiscard_FlushBit & flagsBitfield) {
1507 fDrawBuffer->reset();
1508 } else {
1509 flushDrawBuffer();
1510 }
1511
1512 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001513 fGpu->forceRenderTargetFlush();
1514 }
1515}
1516
1517void GrContext::flushText() {
1518 if (kText_DrawCategory == fLastDrawCategory) {
1519 flushDrawBuffer();
1520 }
1521}
1522
1523void GrContext::flushDrawBuffer() {
1524#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001525 if (fDrawBuffer) {
1526 fDrawBuffer->playback(fGpu);
1527 fDrawBuffer->reset();
1528 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001529#endif
1530}
1531
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001532bool GrContext::readTexturePixels(GrTexture* texture,
1533 int left, int top, int width, int height,
1534 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001535 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001536
1537 // TODO: code read pixels for textures that aren't rendertargets
1538
1539 this->flush();
1540 GrRenderTarget* target = texture->asRenderTarget();
1541 if (NULL != target) {
1542 return fGpu->readPixels(target,
1543 left, top, width, height,
1544 config, buffer);
1545 } else {
1546 return false;
1547 }
1548}
1549
1550bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1551 int left, int top, int width, int height,
1552 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001553 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001554 uint32_t flushFlags = 0;
1555 if (NULL == target) {
1556 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1557 }
1558
1559 this->flush(flushFlags);
1560 return fGpu->readPixels(target,
1561 left, top, width, height,
1562 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001563}
1564
1565void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001566 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001567 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001568 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001569
1570 // TODO: when underlying api has a direct way to do this we should use it
1571 // (e.g. glDrawPixels on desktop GL).
1572
bsalomon@google.com5c638652011-07-18 19:31:59 +00001573 this->flush(true);
1574
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001575 const GrTextureDesc desc = {
1576 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001577 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001578 GrAutoScratchTexture ast(this, desc);
1579 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001580 if (NULL == texture) {
1581 return;
1582 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001583 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001584
bsalomon@google.com27847de2011-02-22 20:59:41 +00001585 GrDrawTarget::AutoStateRestore asr(fGpu);
1586
1587 GrMatrix matrix;
1588 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1589 fGpu->setViewMatrix(matrix);
1590
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001591 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001592 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1593 fGpu->setAlpha(0xFF);
1594 fGpu->setBlendFunc(kOne_BlendCoeff,
1595 kZero_BlendCoeff);
1596 fGpu->setTexture(0, texture);
1597
1598 GrSamplerState sampler;
1599 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001600 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001601 sampler.setMatrix(matrix);
1602 fGpu->setSamplerState(0, sampler);
1603
1604 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1605 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001606 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001607 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1608 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001609 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001610 return;
1611 }
1612 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1613 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1614}
1615////////////////////////////////////////////////////////////////////////////////
1616
1617void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001618
1619 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1620 int s = i + GrPaint::kFirstTextureStage;
1621 target->setTexture(s, paint.getTexture(i));
1622 target->setSamplerState(s, *paint.getTextureSampler(i));
1623 }
1624
1625 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1626
1627 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1628 int s = i + GrPaint::kFirstMaskStage;
1629 target->setTexture(s, paint.getMask(i));
1630 target->setSamplerState(s, *paint.getMaskSampler(i));
1631 }
1632
bsalomon@google.com27847de2011-02-22 20:59:41 +00001633 target->setColor(paint.fColor);
1634
1635 if (paint.fDither) {
1636 target->enableState(GrDrawTarget::kDither_StateBit);
1637 } else {
1638 target->disableState(GrDrawTarget::kDither_StateBit);
1639 }
1640 if (paint.fAntiAlias) {
1641 target->enableState(GrDrawTarget::kAntialias_StateBit);
1642 } else {
1643 target->disableState(GrDrawTarget::kAntialias_StateBit);
1644 }
1645 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001646 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001647}
1648
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001649GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001650 DrawCategory category) {
1651 if (category != fLastDrawCategory) {
1652 flushDrawBuffer();
1653 fLastDrawCategory = category;
1654 }
1655 SetPaint(paint, fGpu);
1656 GrDrawTarget* target = fGpu;
1657 switch (category) {
1658 case kText_DrawCategory:
1659#if DEFER_TEXT_RENDERING
1660 target = fDrawBuffer;
1661 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1662#else
1663 target = fGpu;
1664#endif
1665 break;
1666 case kUnbuffered_DrawCategory:
1667 target = fGpu;
1668 break;
1669 case kBuffered_DrawCategory:
1670 target = fDrawBuffer;
1671 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1672 break;
1673 }
1674 return target;
1675}
1676
bsalomon@google.com30085192011-08-19 15:42:31 +00001677GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1678 const GrPath& path,
1679 GrPathFill fill) {
1680 if (NULL == fPathRendererChain) {
1681 fPathRendererChain =
1682 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1683 }
1684 return fPathRendererChain->getPathRenderer(target, path, fill);
1685}
1686
bsalomon@google.com27847de2011-02-22 20:59:41 +00001687////////////////////////////////////////////////////////////////////////////////
1688
bsalomon@google.com27847de2011-02-22 20:59:41 +00001689void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001690 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001691 fGpu->setRenderTarget(target);
1692}
1693
1694GrRenderTarget* GrContext::getRenderTarget() {
1695 return fGpu->getRenderTarget();
1696}
1697
1698const GrRenderTarget* GrContext::getRenderTarget() const {
1699 return fGpu->getRenderTarget();
1700}
1701
1702const GrMatrix& GrContext::getMatrix() const {
1703 return fGpu->getViewMatrix();
1704}
1705
1706void GrContext::setMatrix(const GrMatrix& m) {
1707 fGpu->setViewMatrix(m);
1708}
1709
1710void GrContext::concatMatrix(const GrMatrix& m) const {
1711 fGpu->preConcatViewMatrix(m);
1712}
1713
1714static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1715 intptr_t mask = 1 << shift;
1716 if (pred) {
1717 bits |= mask;
1718 } else {
1719 bits &= ~mask;
1720 }
1721 return bits;
1722}
1723
1724void GrContext::resetStats() {
1725 fGpu->resetStats();
1726}
1727
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001728const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001729 return fGpu->getStats();
1730}
1731
1732void GrContext::printStats() const {
1733 fGpu->printStats();
1734}
1735
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001736GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001737 fGpu = gpu;
1738 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001739 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001740
bsalomon@google.com30085192011-08-19 15:42:31 +00001741 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001742
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001743 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1744 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001745 fFontCache = new GrFontCache(fGpu);
1746
1747 fLastDrawCategory = kUnbuffered_DrawCategory;
1748
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001749 fDrawBuffer = NULL;
1750 fDrawBufferVBAllocPool = NULL;
1751 fDrawBufferIBAllocPool = NULL;
1752
bsalomon@google.com205d4602011-04-25 12:43:45 +00001753 fAAFillRectIndexBuffer = NULL;
1754 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001755
1756 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1757 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1758 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1759 }
1760 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001761
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001762 this->setupDrawBuffer();
1763}
1764
1765void GrContext::setupDrawBuffer() {
1766
1767 GrAssert(NULL == fDrawBuffer);
1768 GrAssert(NULL == fDrawBufferVBAllocPool);
1769 GrAssert(NULL == fDrawBufferIBAllocPool);
1770
bsalomon@google.com27847de2011-02-22 20:59:41 +00001771#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001772 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001773 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001774 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1775 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001776 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001777 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001778 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001779 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1780
bsalomon@google.com471d4712011-08-23 15:45:25 +00001781 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1782 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001783 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001784#endif
1785
1786#if BATCH_RECT_TO_RECT
1787 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1788#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001789}
1790
bsalomon@google.com27847de2011-02-22 20:59:41 +00001791GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1792 GrDrawTarget* target;
1793#if DEFER_TEXT_RENDERING
1794 target = prepareToDraw(paint, kText_DrawCategory);
1795#else
1796 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1797#endif
1798 SetPaint(paint, target);
1799 return target;
1800}
1801
1802const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1803 return fGpu->getQuadIndexBuffer();
1804}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001805
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001806void GrContext::convolveInX(GrTexture* texture,
1807 const SkRect& rect,
1808 const float* kernel,
1809 int kernelWidth) {
1810 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1811 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1812}
1813
1814void GrContext::convolveInY(GrTexture* texture,
1815 const SkRect& rect,
1816 const float* kernel,
1817 int kernelWidth) {
1818 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1819 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1820}
1821
1822void GrContext::convolve(GrTexture* texture,
1823 const SkRect& rect,
1824 float imageIncrement[2],
1825 const float* kernel,
1826 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001827 GrDrawTarget::AutoStateRestore asr(fGpu);
1828 GrMatrix sampleM;
1829 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1830 GrSamplerState::kClamp_WrapMode,
1831 GrSamplerState::kConvolution_Filter);
1832 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001833 sampleM.setScale(GR_Scalar1 / texture->width(),
1834 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001835 sampler.setMatrix(sampleM);
1836 fGpu->setSamplerState(0, sampler);
1837 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001838 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001839 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001840 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1841}