blob: 6692023a73718fedcd0c8789136e1436ecf3b55f [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.com471d4712011-08-23 15:45:25 +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.com26c2d0a2011-05-17 20:15:30 +00001381 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1382 texOffsets,
1383 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001384 void* curVertex = geo.vertices();
1385
1386 for (int i = 0; i < vertexCount; ++i) {
1387 *((GrPoint*)curVertex) = positions[i];
1388
1389 if (texOffsets[0] > 0) {
1390 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1391 }
1392 if (colorOffset > 0) {
1393 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1394 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001395 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001396 }
1397 } else {
1398 target->setVertexSourceToArray(layout, positions, vertexCount);
1399 }
1400
bsalomon@google.com91958362011-06-13 17:58:13 +00001401 // we don't currently apply offscreen AA to this path. Need improved
1402 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001403
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001404 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001405 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001406 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001407 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001408 target->drawNonIndexed(primitiveType, 0, vertexCount);
1409 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410}
1411
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001412///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001413
reed@google.com07f3ee12011-05-16 17:21:57 +00001414void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1415 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001418 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1419 if (NULL == pr) {
1420 GrPrintf("Unable to find path renderer compatible with path.\n");
1421 return;
1422 }
1423
bsalomon@google.comee435122011-07-01 14:57:55 +00001424 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1425 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001426
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001427 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001428 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001429
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001430 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001431
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001432 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001433 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1434 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001435 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001436 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001437 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001438 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001439 return;
1440 }
1441 }
reed@google.com70c136e2011-06-03 19:51:26 +00001442
reed@google.com07f3ee12011-05-16 17:21:57 +00001443 GrRect pathBounds = path.getBounds();
1444 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001445 if (NULL != translate) {
1446 pathBounds.offset(*translate);
1447 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001448 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001449 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001450 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001451 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001452 return;
1453 }
1454 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001455 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001456 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1457 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001458 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1459 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1460 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001461 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001462 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1463 }
1464 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001465 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001466 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001467 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1468 GrRect rect;
1469 if (clipIBounds.fTop < bound.fTop) {
1470 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1471 clipIBounds.fRight, bound.fTop);
1472 target->drawSimpleRect(rect, NULL, stageMask);
1473 }
1474 if (clipIBounds.fLeft < bound.fLeft) {
1475 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1476 bound.fLeft, bound.fBottom);
1477 target->drawSimpleRect(rect, NULL, stageMask);
1478 }
1479 if (clipIBounds.fRight > bound.fRight) {
1480 rect.setLTRB(bound.fRight, bound.fTop,
1481 clipIBounds.fRight, bound.fBottom);
1482 target->drawSimpleRect(rect, NULL, stageMask);
1483 }
1484 if (clipIBounds.fBottom > bound.fBottom) {
1485 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1486 clipIBounds.fRight, clipIBounds.fBottom);
1487 target->drawSimpleRect(rect, NULL, stageMask);
1488 }
1489 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001490 return;
1491 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001492 }
1493 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001495
bsalomon@google.com27847de2011-02-22 20:59:41 +00001496////////////////////////////////////////////////////////////////////////////////
1497
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001498bool GrContext::supportsShaders() const {
1499 return fGpu->supportsShaders();
1500}
1501
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001502void GrContext::flush(int flagsBitfield) {
1503 if (kDiscard_FlushBit & flagsBitfield) {
1504 fDrawBuffer->reset();
1505 } else {
1506 flushDrawBuffer();
1507 }
1508
1509 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001510 fGpu->forceRenderTargetFlush();
1511 }
1512}
1513
1514void GrContext::flushText() {
1515 if (kText_DrawCategory == fLastDrawCategory) {
1516 flushDrawBuffer();
1517 }
1518}
1519
1520void GrContext::flushDrawBuffer() {
1521#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001522 if (fDrawBuffer) {
1523 fDrawBuffer->playback(fGpu);
1524 fDrawBuffer->reset();
1525 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001526#endif
1527}
1528
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001529bool GrContext::readTexturePixels(GrTexture* texture,
1530 int left, int top, int width, int height,
1531 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001532 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001533
1534 // TODO: code read pixels for textures that aren't rendertargets
1535
1536 this->flush();
1537 GrRenderTarget* target = texture->asRenderTarget();
1538 if (NULL != target) {
1539 return fGpu->readPixels(target,
1540 left, top, width, height,
1541 config, buffer);
1542 } else {
1543 return false;
1544 }
1545}
1546
1547bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1548 int left, int top, int width, int height,
1549 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001550 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001551 uint32_t flushFlags = 0;
1552 if (NULL == target) {
1553 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1554 }
1555
1556 this->flush(flushFlags);
1557 return fGpu->readPixels(target,
1558 left, top, width, height,
1559 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001560}
1561
1562void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001563 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001564 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001565 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001566
1567 // TODO: when underlying api has a direct way to do this we should use it
1568 // (e.g. glDrawPixels on desktop GL).
1569
bsalomon@google.com5c638652011-07-18 19:31:59 +00001570 this->flush(true);
1571
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001572 const GrTextureDesc desc = {
1573 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001574 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001575 GrAutoScratchTexture ast(this, desc);
1576 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001577 if (NULL == texture) {
1578 return;
1579 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001580 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001581
bsalomon@google.com27847de2011-02-22 20:59:41 +00001582 GrDrawTarget::AutoStateRestore asr(fGpu);
1583
1584 GrMatrix matrix;
1585 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1586 fGpu->setViewMatrix(matrix);
1587
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001588 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001589 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1590 fGpu->setAlpha(0xFF);
1591 fGpu->setBlendFunc(kOne_BlendCoeff,
1592 kZero_BlendCoeff);
1593 fGpu->setTexture(0, texture);
1594
1595 GrSamplerState sampler;
1596 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001597 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001598 sampler.setMatrix(matrix);
1599 fGpu->setSamplerState(0, sampler);
1600
1601 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1602 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001603 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001604 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1605 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001606 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001607 return;
1608 }
1609 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1610 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1611}
1612////////////////////////////////////////////////////////////////////////////////
1613
1614void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001615
1616 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1617 int s = i + GrPaint::kFirstTextureStage;
1618 target->setTexture(s, paint.getTexture(i));
1619 target->setSamplerState(s, *paint.getTextureSampler(i));
1620 }
1621
1622 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1623
1624 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1625 int s = i + GrPaint::kFirstMaskStage;
1626 target->setTexture(s, paint.getMask(i));
1627 target->setSamplerState(s, *paint.getMaskSampler(i));
1628 }
1629
bsalomon@google.com27847de2011-02-22 20:59:41 +00001630 target->setColor(paint.fColor);
1631
1632 if (paint.fDither) {
1633 target->enableState(GrDrawTarget::kDither_StateBit);
1634 } else {
1635 target->disableState(GrDrawTarget::kDither_StateBit);
1636 }
1637 if (paint.fAntiAlias) {
1638 target->enableState(GrDrawTarget::kAntialias_StateBit);
1639 } else {
1640 target->disableState(GrDrawTarget::kAntialias_StateBit);
1641 }
1642 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001643 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001644}
1645
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001646GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001647 DrawCategory category) {
1648 if (category != fLastDrawCategory) {
1649 flushDrawBuffer();
1650 fLastDrawCategory = category;
1651 }
1652 SetPaint(paint, fGpu);
1653 GrDrawTarget* target = fGpu;
1654 switch (category) {
1655 case kText_DrawCategory:
1656#if DEFER_TEXT_RENDERING
1657 target = fDrawBuffer;
1658 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1659#else
1660 target = fGpu;
1661#endif
1662 break;
1663 case kUnbuffered_DrawCategory:
1664 target = fGpu;
1665 break;
1666 case kBuffered_DrawCategory:
1667 target = fDrawBuffer;
1668 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1669 break;
1670 }
1671 return target;
1672}
1673
bsalomon@google.com30085192011-08-19 15:42:31 +00001674GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1675 const GrPath& path,
1676 GrPathFill fill) {
1677 if (NULL == fPathRendererChain) {
1678 fPathRendererChain =
1679 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1680 }
1681 return fPathRendererChain->getPathRenderer(target, path, fill);
1682}
1683
bsalomon@google.com27847de2011-02-22 20:59:41 +00001684////////////////////////////////////////////////////////////////////////////////
1685
bsalomon@google.com27847de2011-02-22 20:59:41 +00001686void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001687 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001688 fGpu->setRenderTarget(target);
1689}
1690
1691GrRenderTarget* GrContext::getRenderTarget() {
1692 return fGpu->getRenderTarget();
1693}
1694
1695const GrRenderTarget* GrContext::getRenderTarget() const {
1696 return fGpu->getRenderTarget();
1697}
1698
1699const GrMatrix& GrContext::getMatrix() const {
1700 return fGpu->getViewMatrix();
1701}
1702
1703void GrContext::setMatrix(const GrMatrix& m) {
1704 fGpu->setViewMatrix(m);
1705}
1706
1707void GrContext::concatMatrix(const GrMatrix& m) const {
1708 fGpu->preConcatViewMatrix(m);
1709}
1710
1711static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1712 intptr_t mask = 1 << shift;
1713 if (pred) {
1714 bits |= mask;
1715 } else {
1716 bits &= ~mask;
1717 }
1718 return bits;
1719}
1720
1721void GrContext::resetStats() {
1722 fGpu->resetStats();
1723}
1724
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001725const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001726 return fGpu->getStats();
1727}
1728
1729void GrContext::printStats() const {
1730 fGpu->printStats();
1731}
1732
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001733GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001734 fGpu = gpu;
1735 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001736 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001737
bsalomon@google.com30085192011-08-19 15:42:31 +00001738 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001739
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001740 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1741 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001742 fFontCache = new GrFontCache(fGpu);
1743
1744 fLastDrawCategory = kUnbuffered_DrawCategory;
1745
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001746 fDrawBuffer = NULL;
1747 fDrawBufferVBAllocPool = NULL;
1748 fDrawBufferIBAllocPool = NULL;
1749
bsalomon@google.com205d4602011-04-25 12:43:45 +00001750 fAAFillRectIndexBuffer = NULL;
1751 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001752
1753 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1754 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1755 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1756 }
1757 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001758
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001759 this->setupDrawBuffer();
1760}
1761
1762void GrContext::setupDrawBuffer() {
1763
1764 GrAssert(NULL == fDrawBuffer);
1765 GrAssert(NULL == fDrawBufferVBAllocPool);
1766 GrAssert(NULL == fDrawBufferIBAllocPool);
1767
bsalomon@google.com27847de2011-02-22 20:59:41 +00001768#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001769 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001770 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001771 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1772 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001773 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001774 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001775 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001776 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1777
bsalomon@google.com471d4712011-08-23 15:45:25 +00001778 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1779 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001780 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001781#endif
1782
1783#if BATCH_RECT_TO_RECT
1784 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1785#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001786}
1787
bsalomon@google.com27847de2011-02-22 20:59:41 +00001788GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1789 GrDrawTarget* target;
1790#if DEFER_TEXT_RENDERING
1791 target = prepareToDraw(paint, kText_DrawCategory);
1792#else
1793 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1794#endif
1795 SetPaint(paint, target);
1796 return target;
1797}
1798
1799const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1800 return fGpu->getQuadIndexBuffer();
1801}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001802
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001803void GrContext::convolveInX(GrTexture* texture,
1804 const SkRect& rect,
1805 const float* kernel,
1806 int kernelWidth) {
1807 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1808 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1809}
1810
1811void GrContext::convolveInY(GrTexture* texture,
1812 const SkRect& rect,
1813 const float* kernel,
1814 int kernelWidth) {
1815 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1816 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1817}
1818
1819void GrContext::convolve(GrTexture* texture,
1820 const SkRect& rect,
1821 float imageIncrement[2],
1822 const float* kernel,
1823 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001824 GrDrawTarget::AutoStateRestore asr(fGpu);
1825 GrMatrix sampleM;
1826 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1827 GrSamplerState::kClamp_WrapMode,
1828 GrSamplerState::kConvolution_Filter);
1829 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001830 sampleM.setScale(GR_Scalar1 / texture->width(),
1831 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001832 sampler.setMatrix(sampleM);
1833 fGpu->setSamplerState(0, sampler);
1834 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001835 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001836 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001837 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1838}