blob: b857dda8f7b4ed1a969efe638e1a022c41d9d0fc [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
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000696 desc.fWidth *= record->fScale;
697 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000698 record->fOffscreen0.set(this, desc);
699 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000700 return false;
701 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000702 // the approximate lookup might have given us some slop space, might as well
703 // use it when computing the tiles size.
704 // these are scale values, will adjust after considering
705 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000706 record->fTileSizeX = record->fOffscreen0.texture()->width();
707 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000708
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000709 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000710 desc.fWidth /= 2;
711 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000712 record->fOffscreen1.set(this, desc);
713 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000714 return false;
715 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000716 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000717 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000718 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000719 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000720 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000721 record->fTileSizeX /= record->fScale;
722 record->fTileSizeY /= record->fScale;
723
724 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
725 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
726
tomhudson@google.com237a4612011-07-19 15:44:00 +0000727 record->fClip = target->getClip();
728
bsalomon@google.com91958362011-06-13 17:58:13 +0000729 target->saveCurrentDrawState(&record->fSavedState);
730 return true;
731}
732
733void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
734 const GrIRect& boundRect,
735 int tileX, int tileY,
736 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000737
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000738 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000739 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000740
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000741 GrPaint tempPaint;
742 tempPaint.reset();
743 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000744 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000745
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000746 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000747 int left = boundRect.fLeft + tileX * record->fTileSizeX;
748 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000749 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000750 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000751 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000752 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000753 target->postConcatViewMatrix(scaleM);
754
bsalomon@google.com91958362011-06-13 17:58:13 +0000755 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000756 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000757 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000758 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000759 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
760 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000761 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000762#if 0
763 // visualize tile boundaries by setting edges of offscreen to white
764 // and interior to tranparent. black.
765 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000766
bsalomon@google.com91958362011-06-13 17:58:13 +0000767 static const int gOffset = 2;
768 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
769 record->fScale * w - gOffset,
770 record->fScale * h - gOffset);
771 target->clear(&clear2, 0x0);
772#else
773 target->clear(&clear, 0x0);
774#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000775}
776
bsalomon@google.com91958362011-06-13 17:58:13 +0000777void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000778 const GrPaint& paint,
779 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000780 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000781 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000782 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000783 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000784 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000785 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000786 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
787 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000788 tileRect.fRight = (tileX == record->fTileCountX-1) ?
789 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000790 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000791 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
792 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000793 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000794
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000795 GrSamplerState::Filter filter;
796 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
797 filter = GrSamplerState::k4x4Downsample_Filter;
798 } else {
799 filter = GrSamplerState::kBilinear_Filter;
800 }
801
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000802 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000803 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000804 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000805
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000806 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000807 int scale;
808
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000809 enum {
810 kOffscreenStage = GrPaint::kTotalStages,
811 };
812
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000813 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000814 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000815 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000816 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000817
818 // Do 2x2 downsample from first to second
819 target->setTexture(kOffscreenStage, src);
820 target->setRenderTarget(dst);
821 target->setViewMatrix(GrMatrix::I());
822 sampleM.setScale(scale * GR_Scalar1 / src->width(),
823 scale * GR_Scalar1 / src->height());
824 sampler.setMatrix(sampleM);
825 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000826 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
827 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000828 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
829
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000830 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000831 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000832 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000833 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000834 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000835 } else {
836 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
837 record->fDownsample);
838 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000839 }
840
bsalomon@google.com91958362011-06-13 17:58:13 +0000841 // setup for draw back to main RT, we use the original
842 // draw state setup by the caller plus an additional coverage
843 // stage to handle the AA resolve. Also, we use an identity
844 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000845 int stageMask = paint.getActiveStageMask();
846
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000847 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000848 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000849
850 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 GrMatrix invVM;
852 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000853 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000854 }
855 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000856 // This is important when tiling, otherwise second tile's
857 // pass 1 view matrix will be incorrect.
858 GrDrawTarget::AutoViewMatrixRestore avmr(target);
859
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000860 target->setViewMatrix(GrMatrix::I());
861
862 target->setTexture(kOffscreenStage, src);
863 sampleM.setScale(scale * GR_Scalar1 / src->width(),
864 scale * GR_Scalar1 / src->height());
865 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000866 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000867 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000868 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000869
reed@google.com20efde72011-05-09 17:00:02 +0000870 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000871 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000872 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000873 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000874}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000875
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000876void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
877 GrPathRenderer* pr,
878 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000879 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000880}
881
882////////////////////////////////////////////////////////////////////////////////
883
bsalomon@google.com27847de2011-02-22 20:59:41 +0000884/* create a triangle strip that strokes the specified triangle. There are 8
885 unique vertices, but we repreat the last 2 to close up. Alternatively we
886 could use an indices array, and then only send 8 verts, but not sure that
887 would be faster.
888 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000889static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000890 GrScalar width) {
891 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000892 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000893
894 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
895 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
896 verts[2].set(rect.fRight - rad, rect.fTop + rad);
897 verts[3].set(rect.fRight + rad, rect.fTop - rad);
898 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
899 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
900 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
901 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
902 verts[8] = verts[0];
903 verts[9] = verts[1];
904}
905
bsalomon@google.com205d4602011-04-25 12:43:45 +0000906static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000907 // FIXME: This was copied from SkGpuDevice, seems like
908 // we should have already smeared a in caller if that
909 // is what is desired.
910 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000911 unsigned a = GrColorUnpackA(paint.fColor);
912 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000913 } else {
914 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000915 }
916}
917
918static void setInsetFan(GrPoint* pts, size_t stride,
919 const GrRect& r, GrScalar dx, GrScalar dy) {
920 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
921}
922
923static const uint16_t gFillAARectIdx[] = {
924 0, 1, 5, 5, 4, 0,
925 1, 2, 6, 6, 5, 1,
926 2, 3, 7, 7, 6, 2,
927 3, 0, 4, 4, 7, 3,
928 4, 5, 6, 6, 7, 4,
929};
930
931int GrContext::aaFillRectIndexCount() const {
932 return GR_ARRAY_COUNT(gFillAARectIdx);
933}
934
935GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
936 if (NULL == fAAFillRectIndexBuffer) {
937 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
938 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000939 if (NULL != fAAFillRectIndexBuffer) {
940 #if GR_DEBUG
941 bool updated =
942 #endif
943 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
944 sizeof(gFillAARectIdx));
945 GR_DEBUGASSERT(updated);
946 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000947 }
948 return fAAFillRectIndexBuffer;
949}
950
951static const uint16_t gStrokeAARectIdx[] = {
952 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
953 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
954 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
955 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
956
957 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
958 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
959 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
960 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
961
962 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
963 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
964 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
965 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
966};
967
968int GrContext::aaStrokeRectIndexCount() const {
969 return GR_ARRAY_COUNT(gStrokeAARectIdx);
970}
971
972GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
973 if (NULL == fAAStrokeRectIndexBuffer) {
974 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
975 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000976 if (NULL != fAAStrokeRectIndexBuffer) {
977 #if GR_DEBUG
978 bool updated =
979 #endif
980 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
981 sizeof(gStrokeAARectIdx));
982 GR_DEBUGASSERT(updated);
983 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000984 }
985 return fAAStrokeRectIndexBuffer;
986}
987
988void GrContext::fillAARect(GrDrawTarget* target,
989 const GrPaint& paint,
990 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000991 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
992 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000993
994 size_t vsize = GrDrawTarget::VertexSize(layout);
995
996 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000997 if (!geo.succeeded()) {
998 GrPrintf("Failed to get space for vertices!\n");
999 return;
1000 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001001 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1002 if (NULL == indexBuffer) {
1003 GrPrintf("Failed to create index buffer!\n");
1004 return;
1005 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001006
1007 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1008
1009 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1010 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1011
1012 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1013 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1014
1015 verts += sizeof(GrPoint);
1016 for (int i = 0; i < 4; ++i) {
1017 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1018 }
1019
1020 GrColor innerColor = getColorForMesh(paint);
1021 verts += 4 * vsize;
1022 for (int i = 0; i < 4; ++i) {
1023 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1024 }
1025
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001026 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001027
1028 target->drawIndexed(kTriangles_PrimitiveType, 0,
1029 0, 8, this->aaFillRectIndexCount());
1030}
1031
1032void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1033 const GrRect& devRect, const GrVec& devStrokeSize) {
1034 const GrScalar& dx = devStrokeSize.fX;
1035 const GrScalar& dy = devStrokeSize.fY;
1036 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1037 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1038
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001039 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1040 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001041
1042 GrScalar spare;
1043 {
1044 GrScalar w = devRect.width() - dx;
1045 GrScalar h = devRect.height() - dy;
1046 spare = GrMin(w, h);
1047 }
1048
1049 if (spare <= 0) {
1050 GrRect r(devRect);
1051 r.inset(-rx, -ry);
1052 fillAARect(target, paint, r);
1053 return;
1054 }
1055
1056 size_t vsize = GrDrawTarget::VertexSize(layout);
1057
1058 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001059 if (!geo.succeeded()) {
1060 GrPrintf("Failed to get space for vertices!\n");
1061 return;
1062 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001063 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1064 if (NULL == indexBuffer) {
1065 GrPrintf("Failed to create index buffer!\n");
1066 return;
1067 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001068
1069 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1070
1071 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1072 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1073 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1074 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1075
1076 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1077 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1078 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1079 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1080
1081 verts += sizeof(GrPoint);
1082 for (int i = 0; i < 4; ++i) {
1083 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1084 }
1085
1086 GrColor innerColor = getColorForMesh(paint);
1087 verts += 4 * vsize;
1088 for (int i = 0; i < 8; ++i) {
1089 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1090 }
1091
1092 verts += 8 * vsize;
1093 for (int i = 0; i < 8; ++i) {
1094 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1095 }
1096
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001097 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001098 target->drawIndexed(kTriangles_PrimitiveType,
1099 0, 0, 16, aaStrokeRectIndexCount());
1100}
1101
reed@google.com20efde72011-05-09 17:00:02 +00001102/**
1103 * Returns true if the rects edges are integer-aligned.
1104 */
1105static bool isIRect(const GrRect& r) {
1106 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1107 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1108}
1109
bsalomon@google.com205d4602011-04-25 12:43:45 +00001110static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001111 const GrPaint& paint,
1112 const GrRect& rect,
1113 GrScalar width,
1114 const GrMatrix* matrix,
1115 GrMatrix* combinedMatrix,
1116 GrRect* devRect) {
1117 // we use a simple alpha ramp to do aa on axis-aligned rects
1118 // do AA with alpha ramp if the caller requested AA, the rect
1119 // will be axis-aligned,the render target is not
1120 // multisampled, and the rect won't land on integer coords.
1121
1122 if (!paint.fAntiAlias) {
1123 return false;
1124 }
1125
1126 if (target->getRenderTarget()->isMultisampled()) {
1127 return false;
1128 }
1129
bsalomon@google.com471d4712011-08-23 15:45:25 +00001130 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001131 return false;
1132 }
1133
1134 if (!target->getViewMatrix().preservesAxisAlignment()) {
1135 return false;
1136 }
1137
1138 if (NULL != matrix &&
1139 !matrix->preservesAxisAlignment()) {
1140 return false;
1141 }
1142
1143 *combinedMatrix = target->getViewMatrix();
1144 if (NULL != matrix) {
1145 combinedMatrix->preConcat(*matrix);
1146 GrAssert(combinedMatrix->preservesAxisAlignment());
1147 }
1148
1149 combinedMatrix->mapRect(devRect, rect);
1150 devRect->sort();
1151
1152 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001153 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001154 } else {
1155 return true;
1156 }
1157}
1158
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159void GrContext::drawRect(const GrPaint& paint,
1160 const GrRect& rect,
1161 GrScalar width,
1162 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001163 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001164
1165 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001166 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001167
bsalomon@google.com205d4602011-04-25 12:43:45 +00001168 GrRect devRect = rect;
1169 GrMatrix combinedMatrix;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001170 bool doAA = apply_aa_to_rect(target, paint, rect, width, matrix,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001171 &combinedMatrix, &devRect);
1172
1173 if (doAA) {
1174 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001175 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001176 GrMatrix inv;
1177 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001178 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001179 }
1180 }
1181 target->setViewMatrix(GrMatrix::I());
1182 if (width >= 0) {
1183 GrVec strokeSize;;
1184 if (width > 0) {
1185 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001186 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001187 strokeSize.setAbs(strokeSize);
1188 } else {
1189 strokeSize.set(GR_Scalar1, GR_Scalar1);
1190 }
1191 strokeAARect(target, paint, devRect, strokeSize);
1192 } else {
1193 fillAARect(target, paint, devRect);
1194 }
1195 return;
1196 }
1197
bsalomon@google.com27847de2011-02-22 20:59:41 +00001198 if (width >= 0) {
1199 // TODO: consider making static vertex buffers for these cases.
1200 // Hairline could be done by just adding closing vertex to
1201 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001202 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1203
bsalomon@google.com27847de2011-02-22 20:59:41 +00001204 static const int worstCaseVertCount = 10;
1205 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1206
1207 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001208 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001209 return;
1210 }
1211
1212 GrPrimitiveType primType;
1213 int vertCount;
1214 GrPoint* vertex = geo.positions();
1215
1216 if (width > 0) {
1217 vertCount = 10;
1218 primType = kTriangleStrip_PrimitiveType;
1219 setStrokeRectStrip(vertex, rect, width);
1220 } else {
1221 // hairline
1222 vertCount = 5;
1223 primType = kLineStrip_PrimitiveType;
1224 vertex[0].set(rect.fLeft, rect.fTop);
1225 vertex[1].set(rect.fRight, rect.fTop);
1226 vertex[2].set(rect.fRight, rect.fBottom);
1227 vertex[3].set(rect.fLeft, rect.fBottom);
1228 vertex[4].set(rect.fLeft, rect.fTop);
1229 }
1230
1231 GrDrawTarget::AutoViewMatrixRestore avmr;
1232 if (NULL != matrix) {
1233 avmr.set(target);
1234 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001235 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001236 }
1237
1238 target->drawNonIndexed(primType, 0, vertCount);
1239 } else {
1240 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001241 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001242 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1243 if (NULL == sqVB) {
1244 GrPrintf("Failed to create static rect vb.\n");
1245 return;
1246 }
1247 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001248 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1249 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001250 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001251 0, rect.height(), rect.fTop,
1252 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001253
1254 if (NULL != matrix) {
1255 m.postConcat(*matrix);
1256 }
1257
1258 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001259 target->preConcatSamplerMatrices(stageMask, m);
1260
bsalomon@google.com27847de2011-02-22 20:59:41 +00001261 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1262 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001263 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001264 #endif
1265 }
1266}
1267
1268void GrContext::drawRectToRect(const GrPaint& paint,
1269 const GrRect& dstRect,
1270 const GrRect& srcRect,
1271 const GrMatrix* dstMatrix,
1272 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001273 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001274
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001275 // srcRect refers to paint's first texture
1276 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001277 drawRect(paint, dstRect, -1, dstMatrix);
1278 return;
1279 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001280
bsalomon@google.com27847de2011-02-22 20:59:41 +00001281 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1282
1283#if GR_STATIC_RECT_VB
1284 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001285
1286 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1288
1289 GrMatrix m;
1290
1291 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1292 0, dstRect.height(), dstRect.fTop,
1293 0, 0, GrMatrix::I()[8]);
1294 if (NULL != dstMatrix) {
1295 m.postConcat(*dstMatrix);
1296 }
1297 target->preConcatViewMatrix(m);
1298
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001299 // srcRect refers to first stage
1300 int otherStageMask = paint.getActiveStageMask() &
1301 (~(1 << GrPaint::kFirstTextureStage));
1302 if (otherStageMask) {
1303 target->preConcatSamplerMatrices(otherStageMask, m);
1304 }
1305
bsalomon@google.com27847de2011-02-22 20:59:41 +00001306 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1307 0, srcRect.height(), srcRect.fTop,
1308 0, 0, GrMatrix::I()[8]);
1309 if (NULL != srcMatrix) {
1310 m.postConcat(*srcMatrix);
1311 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001312 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001313
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001314 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1315 if (NULL == sqVB) {
1316 GrPrintf("Failed to create static rect vb.\n");
1317 return;
1318 }
1319 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001320 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1321#else
1322
1323 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001324#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001325 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001326#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1328#endif
1329
1330 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1331 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1332 srcRects[0] = &srcRect;
1333 srcMatrices[0] = srcMatrix;
1334
1335 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1336#endif
1337}
1338
1339void GrContext::drawVertices(const GrPaint& paint,
1340 GrPrimitiveType primitiveType,
1341 int vertexCount,
1342 const GrPoint positions[],
1343 const GrPoint texCoords[],
1344 const GrColor colors[],
1345 const uint16_t indices[],
1346 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001347 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001348
1349 GrDrawTarget::AutoReleaseGeometry geo;
1350
1351 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1352
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001353 bool hasTexCoords[GrPaint::kTotalStages] = {
1354 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1355 0 // remaining stages use positions
1356 };
1357
1358 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001359
1360 if (NULL != colors) {
1361 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001362 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001363 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001364
1365 if (sizeof(GrPoint) != vertexSize) {
1366 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001367 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001368 return;
1369 }
1370 int texOffsets[GrDrawTarget::kMaxTexCoords];
1371 int colorOffset;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001372 int edgeOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001373 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1374 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001375 &colorOffset,
1376 &edgeOffset);
1377 GrAssert(-1 == edgeOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001378 void* curVertex = geo.vertices();
1379
1380 for (int i = 0; i < vertexCount; ++i) {
1381 *((GrPoint*)curVertex) = positions[i];
1382
1383 if (texOffsets[0] > 0) {
1384 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1385 }
1386 if (colorOffset > 0) {
1387 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1388 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001389 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001390 }
1391 } else {
1392 target->setVertexSourceToArray(layout, positions, vertexCount);
1393 }
1394
bsalomon@google.com91958362011-06-13 17:58:13 +00001395 // we don't currently apply offscreen AA to this path. Need improved
1396 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001397
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001398 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001399 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001400 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001401 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001402 target->drawNonIndexed(primitiveType, 0, vertexCount);
1403 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001404}
1405
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001406///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001407
reed@google.com07f3ee12011-05-16 17:21:57 +00001408void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1409 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001412 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1413 if (NULL == pr) {
1414 GrPrintf("Unable to find path renderer compatible with path.\n");
1415 return;
1416 }
1417
bsalomon@google.comee435122011-07-01 14:57:55 +00001418 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1419 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001421 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001422 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001423
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001424 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001425
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001426 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001427 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1428 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001429 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001430 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001431 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001432 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001433 return;
1434 }
1435 }
reed@google.com70c136e2011-06-03 19:51:26 +00001436
reed@google.com07f3ee12011-05-16 17:21:57 +00001437 GrRect pathBounds = path.getBounds();
1438 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001439 if (NULL != translate) {
1440 pathBounds.offset(*translate);
1441 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001442 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001443 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001444 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001445 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001446 return;
1447 }
1448 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001449 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001450 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1451 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001452 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1453 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1454 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001455 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001456 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1457 }
1458 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001459 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001460 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001461 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1462 GrRect rect;
1463 if (clipIBounds.fTop < bound.fTop) {
1464 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1465 clipIBounds.fRight, bound.fTop);
1466 target->drawSimpleRect(rect, NULL, stageMask);
1467 }
1468 if (clipIBounds.fLeft < bound.fLeft) {
1469 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1470 bound.fLeft, bound.fBottom);
1471 target->drawSimpleRect(rect, NULL, stageMask);
1472 }
1473 if (clipIBounds.fRight > bound.fRight) {
1474 rect.setLTRB(bound.fRight, bound.fTop,
1475 clipIBounds.fRight, bound.fBottom);
1476 target->drawSimpleRect(rect, NULL, stageMask);
1477 }
1478 if (clipIBounds.fBottom > bound.fBottom) {
1479 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1480 clipIBounds.fRight, clipIBounds.fBottom);
1481 target->drawSimpleRect(rect, NULL, stageMask);
1482 }
1483 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001484 return;
1485 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001486 }
1487 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001488}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001489
bsalomon@google.com27847de2011-02-22 20:59:41 +00001490////////////////////////////////////////////////////////////////////////////////
1491
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001492bool GrContext::supportsShaders() const {
1493 return fGpu->supportsShaders();
1494}
1495
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001496void GrContext::flush(int flagsBitfield) {
1497 if (kDiscard_FlushBit & flagsBitfield) {
1498 fDrawBuffer->reset();
1499 } else {
1500 flushDrawBuffer();
1501 }
1502
1503 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001504 fGpu->forceRenderTargetFlush();
1505 }
1506}
1507
1508void GrContext::flushText() {
1509 if (kText_DrawCategory == fLastDrawCategory) {
1510 flushDrawBuffer();
1511 }
1512}
1513
1514void GrContext::flushDrawBuffer() {
1515#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001516 if (fDrawBuffer) {
1517 fDrawBuffer->playback(fGpu);
1518 fDrawBuffer->reset();
1519 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001520#endif
1521}
1522
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001523bool GrContext::readTexturePixels(GrTexture* texture,
1524 int left, int top, int width, int height,
1525 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001526 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001527
1528 // TODO: code read pixels for textures that aren't rendertargets
1529
1530 this->flush();
1531 GrRenderTarget* target = texture->asRenderTarget();
1532 if (NULL != target) {
1533 return fGpu->readPixels(target,
1534 left, top, width, height,
1535 config, buffer);
1536 } else {
1537 return false;
1538 }
1539}
1540
1541bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1542 int left, int top, int width, int height,
1543 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001544 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001545 uint32_t flushFlags = 0;
1546 if (NULL == target) {
1547 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1548 }
1549
1550 this->flush(flushFlags);
1551 return fGpu->readPixels(target,
1552 left, top, width, height,
1553 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001554}
1555
1556void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001557 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001558 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001559 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001560
1561 // TODO: when underlying api has a direct way to do this we should use it
1562 // (e.g. glDrawPixels on desktop GL).
1563
bsalomon@google.com5c638652011-07-18 19:31:59 +00001564 this->flush(true);
1565
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001566 const GrTextureDesc desc = {
1567 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001568 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001569 GrAutoScratchTexture ast(this, desc);
1570 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001571 if (NULL == texture) {
1572 return;
1573 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001574 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001575
bsalomon@google.com27847de2011-02-22 20:59:41 +00001576 GrDrawTarget::AutoStateRestore asr(fGpu);
1577
1578 GrMatrix matrix;
1579 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1580 fGpu->setViewMatrix(matrix);
1581
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001582 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001583 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1584 fGpu->setAlpha(0xFF);
1585 fGpu->setBlendFunc(kOne_BlendCoeff,
1586 kZero_BlendCoeff);
1587 fGpu->setTexture(0, texture);
1588
1589 GrSamplerState sampler;
1590 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001591 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001592 sampler.setMatrix(matrix);
1593 fGpu->setSamplerState(0, sampler);
1594
1595 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1596 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001597 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001598 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1599 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001600 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001601 return;
1602 }
1603 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1604 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1605}
1606////////////////////////////////////////////////////////////////////////////////
1607
1608void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001609
1610 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1611 int s = i + GrPaint::kFirstTextureStage;
1612 target->setTexture(s, paint.getTexture(i));
1613 target->setSamplerState(s, *paint.getTextureSampler(i));
1614 }
1615
1616 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1617
1618 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1619 int s = i + GrPaint::kFirstMaskStage;
1620 target->setTexture(s, paint.getMask(i));
1621 target->setSamplerState(s, *paint.getMaskSampler(i));
1622 }
1623
bsalomon@google.com27847de2011-02-22 20:59:41 +00001624 target->setColor(paint.fColor);
1625
1626 if (paint.fDither) {
1627 target->enableState(GrDrawTarget::kDither_StateBit);
1628 } else {
1629 target->disableState(GrDrawTarget::kDither_StateBit);
1630 }
1631 if (paint.fAntiAlias) {
1632 target->enableState(GrDrawTarget::kAntialias_StateBit);
1633 } else {
1634 target->disableState(GrDrawTarget::kAntialias_StateBit);
1635 }
1636 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001637 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001638}
1639
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001640GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001641 DrawCategory category) {
1642 if (category != fLastDrawCategory) {
1643 flushDrawBuffer();
1644 fLastDrawCategory = category;
1645 }
1646 SetPaint(paint, fGpu);
1647 GrDrawTarget* target = fGpu;
1648 switch (category) {
1649 case kText_DrawCategory:
1650#if DEFER_TEXT_RENDERING
1651 target = fDrawBuffer;
1652 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1653#else
1654 target = fGpu;
1655#endif
1656 break;
1657 case kUnbuffered_DrawCategory:
1658 target = fGpu;
1659 break;
1660 case kBuffered_DrawCategory:
1661 target = fDrawBuffer;
1662 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1663 break;
1664 }
1665 return target;
1666}
1667
bsalomon@google.com30085192011-08-19 15:42:31 +00001668GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1669 const GrPath& path,
1670 GrPathFill fill) {
1671 if (NULL == fPathRendererChain) {
1672 fPathRendererChain =
1673 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1674 }
1675 return fPathRendererChain->getPathRenderer(target, path, fill);
1676}
1677
bsalomon@google.com27847de2011-02-22 20:59:41 +00001678////////////////////////////////////////////////////////////////////////////////
1679
bsalomon@google.com27847de2011-02-22 20:59:41 +00001680void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001681 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001682 fGpu->setRenderTarget(target);
1683}
1684
1685GrRenderTarget* GrContext::getRenderTarget() {
1686 return fGpu->getRenderTarget();
1687}
1688
1689const GrRenderTarget* GrContext::getRenderTarget() const {
1690 return fGpu->getRenderTarget();
1691}
1692
1693const GrMatrix& GrContext::getMatrix() const {
1694 return fGpu->getViewMatrix();
1695}
1696
1697void GrContext::setMatrix(const GrMatrix& m) {
1698 fGpu->setViewMatrix(m);
1699}
1700
1701void GrContext::concatMatrix(const GrMatrix& m) const {
1702 fGpu->preConcatViewMatrix(m);
1703}
1704
1705static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1706 intptr_t mask = 1 << shift;
1707 if (pred) {
1708 bits |= mask;
1709 } else {
1710 bits &= ~mask;
1711 }
1712 return bits;
1713}
1714
1715void GrContext::resetStats() {
1716 fGpu->resetStats();
1717}
1718
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001719const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001720 return fGpu->getStats();
1721}
1722
1723void GrContext::printStats() const {
1724 fGpu->printStats();
1725}
1726
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001727GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001728 fGpu = gpu;
1729 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001730 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001731
bsalomon@google.com30085192011-08-19 15:42:31 +00001732 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001733
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001734 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1735 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001736 fFontCache = new GrFontCache(fGpu);
1737
1738 fLastDrawCategory = kUnbuffered_DrawCategory;
1739
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001740 fDrawBuffer = NULL;
1741 fDrawBufferVBAllocPool = NULL;
1742 fDrawBufferIBAllocPool = NULL;
1743
bsalomon@google.com205d4602011-04-25 12:43:45 +00001744 fAAFillRectIndexBuffer = NULL;
1745 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001746
1747 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1748 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1749 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1750 }
1751 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001752
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001753 this->setupDrawBuffer();
1754}
1755
1756void GrContext::setupDrawBuffer() {
1757
1758 GrAssert(NULL == fDrawBuffer);
1759 GrAssert(NULL == fDrawBufferVBAllocPool);
1760 GrAssert(NULL == fDrawBufferIBAllocPool);
1761
bsalomon@google.com27847de2011-02-22 20:59:41 +00001762#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001763 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001764 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001765 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1766 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001767 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001768 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001769 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001770 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1771
bsalomon@google.com471d4712011-08-23 15:45:25 +00001772 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1773 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001774 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001775#endif
1776
1777#if BATCH_RECT_TO_RECT
1778 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1779#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001780}
1781
bsalomon@google.com27847de2011-02-22 20:59:41 +00001782GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1783 GrDrawTarget* target;
1784#if DEFER_TEXT_RENDERING
1785 target = prepareToDraw(paint, kText_DrawCategory);
1786#else
1787 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1788#endif
1789 SetPaint(paint, target);
1790 return target;
1791}
1792
1793const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1794 return fGpu->getQuadIndexBuffer();
1795}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001796
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001797void GrContext::convolveInX(GrTexture* texture,
1798 const SkRect& rect,
1799 const float* kernel,
1800 int kernelWidth) {
1801 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1802 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1803}
1804
1805void GrContext::convolveInY(GrTexture* texture,
1806 const SkRect& rect,
1807 const float* kernel,
1808 int kernelWidth) {
1809 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1810 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1811}
1812
1813void GrContext::convolve(GrTexture* texture,
1814 const SkRect& rect,
1815 float imageIncrement[2],
1816 const float* kernel,
1817 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001818 GrDrawTarget::AutoStateRestore asr(fGpu);
1819 GrMatrix sampleM;
1820 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1821 GrSamplerState::kClamp_WrapMode,
1822 GrSamplerState::kConvolution_Filter);
1823 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001824 sampleM.setScale(GR_Scalar1 / texture->width(),
1825 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001826 sampler.setMatrix(sampleM);
1827 fGpu->setSamplerState(0, sampler);
1828 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001829 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001830 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001831 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1832}