blob: a97c857490ea88a34d37277a61c4d67ed00e2e32 [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.com5877ffd2011-04-11 17:58:48 +0000551///////////////////////////////////////////////////////////////////////////////
552
bsalomon@google.com27847de2011-02-22 20:59:41 +0000553bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000554 int width, int height) const {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000555 if (!fGpu->supports8BitPalette()) {
556 return false;
557 }
558
559
560 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
561
562 if (!isPow2) {
563 if (!fGpu->npotTextureSupport()) {
564 return false;
565 }
566
567 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
568 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
569 if (tiled && !fGpu->npotTextureTileSupport()) {
570 return false;
571 }
572 }
573 return true;
574}
575
576////////////////////////////////////////////////////////////////////////////////
577
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000578const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
579
bsalomon@google.com27847de2011-02-22 20:59:41 +0000580void GrContext::setClip(const GrClip& clip) {
581 fGpu->setClip(clip);
582 fGpu->enableState(GrDrawTarget::kClip_StateBit);
583}
584
585void GrContext::setClip(const GrIRect& rect) {
586 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000587 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588 fGpu->setClip(clip);
589}
590
591////////////////////////////////////////////////////////////////////////////////
592
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000593void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000594 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000595 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596}
597
598void GrContext::drawPaint(const GrPaint& paint) {
599 // set rect to be big enough to fill the space, but not super-huge, so we
600 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000601 GrRect r;
602 r.setLTRB(0, 0,
603 GrIntToScalar(getRenderTarget()->width()),
604 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000605 GrMatrix inverse;
606 if (fGpu->getViewInverse(&inverse)) {
607 inverse.mapRect(&r);
608 } else {
609 GrPrintf("---- fGpu->getViewInverse failed\n");
610 }
611 this->drawRect(paint, r);
612}
613
bsalomon@google.com205d4602011-04-25 12:43:45 +0000614////////////////////////////////////////////////////////////////////////////////
615
bsalomon@google.com91958362011-06-13 17:58:13 +0000616struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000617 enum Downsample {
618 k4x4TwoPass_Downsample,
619 k4x4SinglePass_Downsample,
620 kFSAA_Downsample
621 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000622 int fTileSizeX;
623 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000624 int fTileCountX;
625 int fTileCountY;
626 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000627 GrAutoScratchTexture fOffscreen0;
628 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000629 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000630 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000631};
632
bsalomon@google.com471d4712011-08-23 15:45:25 +0000633bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000634 const GrPaint& paint,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000635 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000636#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000637 return false;
638#else
639 if (!paint.fAntiAlias) {
640 return false;
641 }
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000642 // Line primitves are always rasterized as 1 pixel wide.
643 // Super-sampling would make them too thin but MSAA would be OK.
644 if (isHairLines &&
645 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA())) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000646 return false;
647 }
648 if (target->getRenderTarget()->isMultisampled()) {
649 return false;
650 }
651 // we have to be sure that the blend equation is expressible
652 // as simple src / dst coeffecients when the source
653 // is already modulated by the coverage fraction.
654 // We could use dual-source blending to get the correct per-pixel
655 // dst coeffecient for the remaining cases.
656 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
657 kOne_BlendCoeff != paint.fDstBlendCoeff &&
658 kISA_BlendCoeff != paint.fDstBlendCoeff) {
659 return false;
660 }
661 return true;
662#endif
663}
664
bsalomon@google.com91958362011-06-13 17:58:13 +0000665bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000666 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000667 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000668 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000669 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000670
671 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000672
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000673 GrAssert(NULL == record->fOffscreen0.texture());
674 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000675 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000676
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000677 int boundW = boundRect.width();
678 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000679
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000680 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000681
682 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
683 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
684
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000685 if (requireStencil) {
686 desc.fFlags = kRenderTarget_GrTextureFlagBit;
687 } else {
688 desc.fFlags = kRenderTarget_GrTextureFlagBit |
689 kNoStencil_GrTextureFlagBit;
690 }
691
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000692 desc.fFormat = kRGBA_8888_GrPixelConfig;
693
bsalomon@google.com91958362011-06-13 17:58:13 +0000694 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000695 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000696 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000697 desc.fAALevel = kMed_GrAALevel;
698 } else {
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000699 record->fDownsample = (fGpu->supportsShaders()) ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000700 OffscreenRecord::k4x4SinglePass_Downsample :
701 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000702 record->fScale = OFFSCREEN_SSAA_SCALE;
703 // both downsample paths assume this
704 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000705 desc.fAALevel = kNone_GrAALevel;
706 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000707 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
708 // of simple circles?
709 if (pr) {
710 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
711 }
712
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000713 desc.fWidth *= record->fScale;
714 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000715 record->fOffscreen0.set(this, desc);
716 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000717 return false;
718 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000719 // the approximate lookup might have given us some slop space, might as well
720 // use it when computing the tiles size.
721 // these are scale values, will adjust after considering
722 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000723 record->fTileSizeX = record->fOffscreen0.texture()->width();
724 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000725
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000726 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000727 desc.fWidth /= 2;
728 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000729 record->fOffscreen1.set(this, desc);
730 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000731 return false;
732 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000733 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000734 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000735 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000736 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000737 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000738 record->fTileSizeX /= record->fScale;
739 record->fTileSizeY /= record->fScale;
740
741 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
742 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
743
tomhudson@google.com237a4612011-07-19 15:44:00 +0000744 record->fClip = target->getClip();
745
bsalomon@google.com91958362011-06-13 17:58:13 +0000746 target->saveCurrentDrawState(&record->fSavedState);
747 return true;
748}
749
750void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
751 const GrIRect& boundRect,
752 int tileX, int tileY,
753 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000754
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000755 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000756 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000757
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000758 GrPaint tempPaint;
759 tempPaint.reset();
760 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000761 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000762
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000763 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000764 int left = boundRect.fLeft + tileX * record->fTileSizeX;
765 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000766 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000767 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000768 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000769 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000770 target->postConcatViewMatrix(scaleM);
771
bsalomon@google.com91958362011-06-13 17:58:13 +0000772 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000773 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000774 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000775 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000776 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
777 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000778 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000779#if 0
780 // visualize tile boundaries by setting edges of offscreen to white
781 // and interior to tranparent. black.
782 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000783
bsalomon@google.com91958362011-06-13 17:58:13 +0000784 static const int gOffset = 2;
785 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
786 record->fScale * w - gOffset,
787 record->fScale * h - gOffset);
788 target->clear(&clear2, 0x0);
789#else
790 target->clear(&clear, 0x0);
791#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000792}
793
bsalomon@google.com91958362011-06-13 17:58:13 +0000794void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795 const GrPaint& paint,
796 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000797 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000798 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000799 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000800 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000801 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000802 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000803 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
804 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000805 tileRect.fRight = (tileX == record->fTileCountX-1) ?
806 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000807 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000808 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
809 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000811
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000812 GrSamplerState::Filter filter;
813 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
814 filter = GrSamplerState::k4x4Downsample_Filter;
815 } else {
816 filter = GrSamplerState::kBilinear_Filter;
817 }
818
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000819 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000820 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000821 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000822
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000823 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000824 int scale;
825
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000826 enum {
827 kOffscreenStage = GrPaint::kTotalStages,
828 };
829
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000830 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000831 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000832 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000833 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000834
835 // Do 2x2 downsample from first to second
836 target->setTexture(kOffscreenStage, src);
837 target->setRenderTarget(dst);
838 target->setViewMatrix(GrMatrix::I());
839 sampleM.setScale(scale * GR_Scalar1 / src->width(),
840 scale * GR_Scalar1 / src->height());
841 sampler.setMatrix(sampleM);
842 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000843 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
844 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000845 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
846
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000847 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000848 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000849 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000850 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000852 } else {
853 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
854 record->fDownsample);
855 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000856 }
857
bsalomon@google.com91958362011-06-13 17:58:13 +0000858 // setup for draw back to main RT, we use the original
859 // draw state setup by the caller plus an additional coverage
860 // stage to handle the AA resolve. Also, we use an identity
861 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000862 int stageMask = paint.getActiveStageMask();
863
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000865 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000866
867 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000868 GrMatrix invVM;
869 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000870 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871 }
872 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000873 // This is important when tiling, otherwise second tile's
874 // pass 1 view matrix will be incorrect.
875 GrDrawTarget::AutoViewMatrixRestore avmr(target);
876
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000877 target->setViewMatrix(GrMatrix::I());
878
879 target->setTexture(kOffscreenStage, src);
880 sampleM.setScale(scale * GR_Scalar1 / src->width(),
881 scale * GR_Scalar1 / src->height());
882 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000883 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000884 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000885 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000886
reed@google.com20efde72011-05-09 17:00:02 +0000887 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000888 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000889 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000890 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000891}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000892
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000893void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
894 GrPathRenderer* pr,
895 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000896 if (pr) {
897 // Counterpart of scale() in prepareForOffscreenAA()
898 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
899 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000900 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000901}
902
903////////////////////////////////////////////////////////////////////////////////
904
bsalomon@google.com27847de2011-02-22 20:59:41 +0000905/* create a triangle strip that strokes the specified triangle. There are 8
906 unique vertices, but we repreat the last 2 to close up. Alternatively we
907 could use an indices array, and then only send 8 verts, but not sure that
908 would be faster.
909 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000910static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000911 GrScalar width) {
912 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000913 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000914
915 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
916 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
917 verts[2].set(rect.fRight - rad, rect.fTop + rad);
918 verts[3].set(rect.fRight + rad, rect.fTop - rad);
919 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
920 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
921 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
922 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
923 verts[8] = verts[0];
924 verts[9] = verts[1];
925}
926
bsalomon@google.com205d4602011-04-25 12:43:45 +0000927static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000928 // FIXME: This was copied from SkGpuDevice, seems like
929 // we should have already smeared a in caller if that
930 // is what is desired.
931 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000932 unsigned a = GrColorUnpackA(paint.fColor);
933 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000934 } else {
935 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000936 }
937}
938
939static void setInsetFan(GrPoint* pts, size_t stride,
940 const GrRect& r, GrScalar dx, GrScalar dy) {
941 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
942}
943
944static const uint16_t gFillAARectIdx[] = {
945 0, 1, 5, 5, 4, 0,
946 1, 2, 6, 6, 5, 1,
947 2, 3, 7, 7, 6, 2,
948 3, 0, 4, 4, 7, 3,
949 4, 5, 6, 6, 7, 4,
950};
951
952int GrContext::aaFillRectIndexCount() const {
953 return GR_ARRAY_COUNT(gFillAARectIdx);
954}
955
956GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
957 if (NULL == fAAFillRectIndexBuffer) {
958 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
959 false);
960 GrAssert(NULL != fAAFillRectIndexBuffer);
961#if GR_DEBUG
962 bool updated =
963#endif
964 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
965 sizeof(gFillAARectIdx));
966 GR_DEBUGASSERT(updated);
967 }
968 return fAAFillRectIndexBuffer;
969}
970
971static const uint16_t gStrokeAARectIdx[] = {
972 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
973 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
974 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
975 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
976
977 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
978 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
979 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
980 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
981
982 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
983 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
984 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
985 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
986};
987
988int GrContext::aaStrokeRectIndexCount() const {
989 return GR_ARRAY_COUNT(gStrokeAARectIdx);
990}
991
992GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
993 if (NULL == fAAStrokeRectIndexBuffer) {
994 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
995 false);
996 GrAssert(NULL != fAAStrokeRectIndexBuffer);
997#if GR_DEBUG
998 bool updated =
999#endif
1000 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1001 sizeof(gStrokeAARectIdx));
1002 GR_DEBUGASSERT(updated);
1003 }
1004 return fAAStrokeRectIndexBuffer;
1005}
1006
1007void GrContext::fillAARect(GrDrawTarget* target,
1008 const GrPaint& paint,
1009 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001010 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1011 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001012
1013 size_t vsize = GrDrawTarget::VertexSize(layout);
1014
1015 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001016 if (!geo.succeeded()) {
1017 GrPrintf("Failed to get space for vertices!\n");
1018 return;
1019 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001020
1021 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1022
1023 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1024 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1025
1026 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1027 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1028
1029 verts += sizeof(GrPoint);
1030 for (int i = 0; i < 4; ++i) {
1031 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1032 }
1033
1034 GrColor innerColor = getColorForMesh(paint);
1035 verts += 4 * vsize;
1036 for (int i = 0; i < 4; ++i) {
1037 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1038 }
1039
1040 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
1041
1042 target->drawIndexed(kTriangles_PrimitiveType, 0,
1043 0, 8, this->aaFillRectIndexCount());
1044}
1045
1046void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1047 const GrRect& devRect, const GrVec& devStrokeSize) {
1048 const GrScalar& dx = devStrokeSize.fX;
1049 const GrScalar& dy = devStrokeSize.fY;
1050 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1051 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1052
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001053 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1054 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001055
1056 GrScalar spare;
1057 {
1058 GrScalar w = devRect.width() - dx;
1059 GrScalar h = devRect.height() - dy;
1060 spare = GrMin(w, h);
1061 }
1062
1063 if (spare <= 0) {
1064 GrRect r(devRect);
1065 r.inset(-rx, -ry);
1066 fillAARect(target, paint, r);
1067 return;
1068 }
1069
1070 size_t vsize = GrDrawTarget::VertexSize(layout);
1071
1072 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001073 if (!geo.succeeded()) {
1074 GrPrintf("Failed to get space for vertices!\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
1106 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1107 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}