blob: 7bac3ba605cbbbbb64d4e8c8a54b04e7aa950362 [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,
554 int width, int height) {
555 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.com471d4712011-08-23 15:45:25 +0000642 if (isHairLines && target->willUseHWAALines()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000643 return false;
644 }
645 if (target->getRenderTarget()->isMultisampled()) {
646 return false;
647 }
648 // we have to be sure that the blend equation is expressible
649 // as simple src / dst coeffecients when the source
650 // is already modulated by the coverage fraction.
651 // We could use dual-source blending to get the correct per-pixel
652 // dst coeffecient for the remaining cases.
653 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
654 kOne_BlendCoeff != paint.fDstBlendCoeff &&
655 kISA_BlendCoeff != paint.fDstBlendCoeff) {
656 return false;
657 }
658 return true;
659#endif
660}
661
bsalomon@google.com91958362011-06-13 17:58:13 +0000662bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000663 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000664 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000665 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000666 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000667
668 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000669
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000670 GrAssert(NULL == record->fOffscreen0.texture());
671 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000672 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000673
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000674 int boundW = boundRect.width();
675 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000676
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000677 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000678
679 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
680 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
681
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000682 if (requireStencil) {
683 desc.fFlags = kRenderTarget_GrTextureFlagBit;
684 } else {
685 desc.fFlags = kRenderTarget_GrTextureFlagBit |
686 kNoStencil_GrTextureFlagBit;
687 }
688
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000689 desc.fFormat = kRGBA_8888_GrPixelConfig;
690
bsalomon@google.com91958362011-06-13 17:58:13 +0000691 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000692 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000693 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000694 desc.fAALevel = kMed_GrAALevel;
695 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000696 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
697 OffscreenRecord::k4x4SinglePass_Downsample :
698 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000699 record->fScale = OFFSCREEN_SSAA_SCALE;
700 // both downsample paths assume this
701 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000702 desc.fAALevel = kNone_GrAALevel;
703 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000704 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
705 // of simple circles?
706 if (pr) {
707 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
708 }
709
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000710 desc.fWidth *= record->fScale;
711 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000712 record->fOffscreen0.set(this, desc);
713 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000714 return false;
715 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000716 // the approximate lookup might have given us some slop space, might as well
717 // use it when computing the tiles size.
718 // these are scale values, will adjust after considering
719 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000720 record->fTileSizeX = record->fOffscreen0.texture()->width();
721 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000722
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000723 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000724 desc.fWidth /= 2;
725 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000726 record->fOffscreen1.set(this, desc);
727 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000728 return false;
729 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000730 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000731 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000732 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000733 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000734 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000735 record->fTileSizeX /= record->fScale;
736 record->fTileSizeY /= record->fScale;
737
738 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
739 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
740
tomhudson@google.com237a4612011-07-19 15:44:00 +0000741 record->fClip = target->getClip();
742
bsalomon@google.com91958362011-06-13 17:58:13 +0000743 target->saveCurrentDrawState(&record->fSavedState);
744 return true;
745}
746
747void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
748 const GrIRect& boundRect,
749 int tileX, int tileY,
750 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000751
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000752 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000753 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000754
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000755 GrPaint tempPaint;
756 tempPaint.reset();
757 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000758 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000759
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000760 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000761 int left = boundRect.fLeft + tileX * record->fTileSizeX;
762 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000763 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000764 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000765 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000766 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000767 target->postConcatViewMatrix(scaleM);
768
bsalomon@google.com91958362011-06-13 17:58:13 +0000769 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000770 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000771 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000772 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000773 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
774 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000775 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000776#if 0
777 // visualize tile boundaries by setting edges of offscreen to white
778 // and interior to tranparent. black.
779 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000780
bsalomon@google.com91958362011-06-13 17:58:13 +0000781 static const int gOffset = 2;
782 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
783 record->fScale * w - gOffset,
784 record->fScale * h - gOffset);
785 target->clear(&clear2, 0x0);
786#else
787 target->clear(&clear, 0x0);
788#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000789}
790
bsalomon@google.com91958362011-06-13 17:58:13 +0000791void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000792 const GrPaint& paint,
793 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000794 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000796 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000797 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000798 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000799 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000800 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
801 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000802 tileRect.fRight = (tileX == record->fTileCountX-1) ?
803 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000804 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000805 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
806 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000807 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000808
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000809 GrSamplerState::Filter filter;
810 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
811 filter = GrSamplerState::k4x4Downsample_Filter;
812 } else {
813 filter = GrSamplerState::kBilinear_Filter;
814 }
815
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000816 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000817 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000818 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000819
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000820 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000821 int scale;
822
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000823 enum {
824 kOffscreenStage = GrPaint::kTotalStages,
825 };
826
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000827 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000828 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000829 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000830 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000831
832 // Do 2x2 downsample from first to second
833 target->setTexture(kOffscreenStage, src);
834 target->setRenderTarget(dst);
835 target->setViewMatrix(GrMatrix::I());
836 sampleM.setScale(scale * GR_Scalar1 / src->width(),
837 scale * GR_Scalar1 / src->height());
838 sampler.setMatrix(sampleM);
839 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000840 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
841 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000842 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
843
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000844 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000845 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000846 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000847 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000848 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000849 } else {
850 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
851 record->fDownsample);
852 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000853 }
854
bsalomon@google.com91958362011-06-13 17:58:13 +0000855 // setup for draw back to main RT, we use the original
856 // draw state setup by the caller plus an additional coverage
857 // stage to handle the AA resolve. Also, we use an identity
858 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000859 int stageMask = paint.getActiveStageMask();
860
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000861 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000862 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000863
864 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000865 GrMatrix invVM;
866 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000867 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000868 }
869 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000870 // This is important when tiling, otherwise second tile's
871 // pass 1 view matrix will be incorrect.
872 GrDrawTarget::AutoViewMatrixRestore avmr(target);
873
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000874 target->setViewMatrix(GrMatrix::I());
875
876 target->setTexture(kOffscreenStage, src);
877 sampleM.setScale(scale * GR_Scalar1 / src->width(),
878 scale * GR_Scalar1 / src->height());
879 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000880 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000881 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000882 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000883
reed@google.com20efde72011-05-09 17:00:02 +0000884 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000885 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000886 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000887 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000888}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000889
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000890void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
891 GrPathRenderer* pr,
892 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000893 if (pr) {
894 // Counterpart of scale() in prepareForOffscreenAA()
895 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
896 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000897 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000898}
899
900////////////////////////////////////////////////////////////////////////////////
901
bsalomon@google.com27847de2011-02-22 20:59:41 +0000902/* create a triangle strip that strokes the specified triangle. There are 8
903 unique vertices, but we repreat the last 2 to close up. Alternatively we
904 could use an indices array, and then only send 8 verts, but not sure that
905 would be faster.
906 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000907static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000908 GrScalar width) {
909 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000910 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000911
912 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
913 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
914 verts[2].set(rect.fRight - rad, rect.fTop + rad);
915 verts[3].set(rect.fRight + rad, rect.fTop - rad);
916 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
917 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
918 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
919 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
920 verts[8] = verts[0];
921 verts[9] = verts[1];
922}
923
bsalomon@google.com205d4602011-04-25 12:43:45 +0000924static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000925 // FIXME: This was copied from SkGpuDevice, seems like
926 // we should have already smeared a in caller if that
927 // is what is desired.
928 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000929 unsigned a = GrColorUnpackA(paint.fColor);
930 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000931 } else {
932 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000933 }
934}
935
936static void setInsetFan(GrPoint* pts, size_t stride,
937 const GrRect& r, GrScalar dx, GrScalar dy) {
938 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
939}
940
941static const uint16_t gFillAARectIdx[] = {
942 0, 1, 5, 5, 4, 0,
943 1, 2, 6, 6, 5, 1,
944 2, 3, 7, 7, 6, 2,
945 3, 0, 4, 4, 7, 3,
946 4, 5, 6, 6, 7, 4,
947};
948
949int GrContext::aaFillRectIndexCount() const {
950 return GR_ARRAY_COUNT(gFillAARectIdx);
951}
952
953GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
954 if (NULL == fAAFillRectIndexBuffer) {
955 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
956 false);
957 GrAssert(NULL != fAAFillRectIndexBuffer);
958#if GR_DEBUG
959 bool updated =
960#endif
961 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
962 sizeof(gFillAARectIdx));
963 GR_DEBUGASSERT(updated);
964 }
965 return fAAFillRectIndexBuffer;
966}
967
968static const uint16_t gStrokeAARectIdx[] = {
969 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
970 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
971 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
972 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
973
974 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
975 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
976 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
977 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
978
979 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
980 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
981 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
982 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
983};
984
985int GrContext::aaStrokeRectIndexCount() const {
986 return GR_ARRAY_COUNT(gStrokeAARectIdx);
987}
988
989GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
990 if (NULL == fAAStrokeRectIndexBuffer) {
991 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
992 false);
993 GrAssert(NULL != fAAStrokeRectIndexBuffer);
994#if GR_DEBUG
995 bool updated =
996#endif
997 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
998 sizeof(gStrokeAARectIdx));
999 GR_DEBUGASSERT(updated);
1000 }
1001 return fAAStrokeRectIndexBuffer;
1002}
1003
1004void GrContext::fillAARect(GrDrawTarget* target,
1005 const GrPaint& paint,
1006 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001007 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1008 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001009
1010 size_t vsize = GrDrawTarget::VertexSize(layout);
1011
1012 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001013 if (!geo.succeeded()) {
1014 GrPrintf("Failed to get space for vertices!\n");
1015 return;
1016 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001017
1018 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1019
1020 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1021 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1022
1023 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1024 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1025
1026 verts += sizeof(GrPoint);
1027 for (int i = 0; i < 4; ++i) {
1028 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1029 }
1030
1031 GrColor innerColor = getColorForMesh(paint);
1032 verts += 4 * vsize;
1033 for (int i = 0; i < 4; ++i) {
1034 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1035 }
1036
1037 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
1038
1039 target->drawIndexed(kTriangles_PrimitiveType, 0,
1040 0, 8, this->aaFillRectIndexCount());
1041}
1042
1043void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1044 const GrRect& devRect, const GrVec& devStrokeSize) {
1045 const GrScalar& dx = devStrokeSize.fX;
1046 const GrScalar& dy = devStrokeSize.fY;
1047 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1048 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1049
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001050 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1051 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001052
1053 GrScalar spare;
1054 {
1055 GrScalar w = devRect.width() - dx;
1056 GrScalar h = devRect.height() - dy;
1057 spare = GrMin(w, h);
1058 }
1059
1060 if (spare <= 0) {
1061 GrRect r(devRect);
1062 r.inset(-rx, -ry);
1063 fillAARect(target, paint, r);
1064 return;
1065 }
1066
1067 size_t vsize = GrDrawTarget::VertexSize(layout);
1068
1069 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001070 if (!geo.succeeded()) {
1071 GrPrintf("Failed to get space for vertices!\n");
1072 return;
1073 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001074
1075 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1076
1077 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1078 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1079 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1080 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1081
1082 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1083 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1084 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1085 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1086
1087 verts += sizeof(GrPoint);
1088 for (int i = 0; i < 4; ++i) {
1089 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1090 }
1091
1092 GrColor innerColor = getColorForMesh(paint);
1093 verts += 4 * vsize;
1094 for (int i = 0; i < 8; ++i) {
1095 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1096 }
1097
1098 verts += 8 * vsize;
1099 for (int i = 0; i < 8; ++i) {
1100 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1101 }
1102
1103 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1104 target->drawIndexed(kTriangles_PrimitiveType,
1105 0, 0, 16, aaStrokeRectIndexCount());
1106}
1107
reed@google.com20efde72011-05-09 17:00:02 +00001108/**
1109 * Returns true if the rects edges are integer-aligned.
1110 */
1111static bool isIRect(const GrRect& r) {
1112 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1113 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1114}
1115
bsalomon@google.com205d4602011-04-25 12:43:45 +00001116static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001117 const GrPaint& paint,
1118 const GrRect& rect,
1119 GrScalar width,
1120 const GrMatrix* matrix,
1121 GrMatrix* combinedMatrix,
1122 GrRect* devRect) {
1123 // we use a simple alpha ramp to do aa on axis-aligned rects
1124 // do AA with alpha ramp if the caller requested AA, the rect
1125 // will be axis-aligned,the render target is not
1126 // multisampled, and the rect won't land on integer coords.
1127
1128 if (!paint.fAntiAlias) {
1129 return false;
1130 }
1131
1132 if (target->getRenderTarget()->isMultisampled()) {
1133 return false;
1134 }
1135
bsalomon@google.com471d4712011-08-23 15:45:25 +00001136 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001137 return false;
1138 }
1139
1140 if (!target->getViewMatrix().preservesAxisAlignment()) {
1141 return false;
1142 }
1143
1144 if (NULL != matrix &&
1145 !matrix->preservesAxisAlignment()) {
1146 return false;
1147 }
1148
1149 *combinedMatrix = target->getViewMatrix();
1150 if (NULL != matrix) {
1151 combinedMatrix->preConcat(*matrix);
1152 GrAssert(combinedMatrix->preservesAxisAlignment());
1153 }
1154
1155 combinedMatrix->mapRect(devRect, rect);
1156 devRect->sort();
1157
1158 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001159 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001160 } else {
1161 return true;
1162 }
1163}
1164
bsalomon@google.com27847de2011-02-22 20:59:41 +00001165void GrContext::drawRect(const GrPaint& paint,
1166 const GrRect& rect,
1167 GrScalar width,
1168 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001169 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001170
1171 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001172 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001173
bsalomon@google.com205d4602011-04-25 12:43:45 +00001174 GrRect devRect = rect;
1175 GrMatrix combinedMatrix;
bsalomon@google.com471d4712011-08-23 15:45:25 +00001176 bool doAA = apply_aa_to_rect(target, paint, rect, width, matrix,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001177 &combinedMatrix, &devRect);
1178
1179 if (doAA) {
1180 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001181 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001182 GrMatrix inv;
1183 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001184 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001185 }
1186 }
1187 target->setViewMatrix(GrMatrix::I());
1188 if (width >= 0) {
1189 GrVec strokeSize;;
1190 if (width > 0) {
1191 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001192 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001193 strokeSize.setAbs(strokeSize);
1194 } else {
1195 strokeSize.set(GR_Scalar1, GR_Scalar1);
1196 }
1197 strokeAARect(target, paint, devRect, strokeSize);
1198 } else {
1199 fillAARect(target, paint, devRect);
1200 }
1201 return;
1202 }
1203
bsalomon@google.com27847de2011-02-22 20:59:41 +00001204 if (width >= 0) {
1205 // TODO: consider making static vertex buffers for these cases.
1206 // Hairline could be done by just adding closing vertex to
1207 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001208 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1209
bsalomon@google.com27847de2011-02-22 20:59:41 +00001210 static const int worstCaseVertCount = 10;
1211 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1212
1213 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001214 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001215 return;
1216 }
1217
1218 GrPrimitiveType primType;
1219 int vertCount;
1220 GrPoint* vertex = geo.positions();
1221
1222 if (width > 0) {
1223 vertCount = 10;
1224 primType = kTriangleStrip_PrimitiveType;
1225 setStrokeRectStrip(vertex, rect, width);
1226 } else {
1227 // hairline
1228 vertCount = 5;
1229 primType = kLineStrip_PrimitiveType;
1230 vertex[0].set(rect.fLeft, rect.fTop);
1231 vertex[1].set(rect.fRight, rect.fTop);
1232 vertex[2].set(rect.fRight, rect.fBottom);
1233 vertex[3].set(rect.fLeft, rect.fBottom);
1234 vertex[4].set(rect.fLeft, rect.fTop);
1235 }
1236
1237 GrDrawTarget::AutoViewMatrixRestore avmr;
1238 if (NULL != matrix) {
1239 avmr.set(target);
1240 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001241 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001242 }
1243
1244 target->drawNonIndexed(primType, 0, vertCount);
1245 } else {
1246 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001247 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001248 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1249 if (NULL == sqVB) {
1250 GrPrintf("Failed to create static rect vb.\n");
1251 return;
1252 }
1253 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001254 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1255 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001256 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001257 0, rect.height(), rect.fTop,
1258 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001259
1260 if (NULL != matrix) {
1261 m.postConcat(*matrix);
1262 }
1263
1264 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001265 target->preConcatSamplerMatrices(stageMask, m);
1266
bsalomon@google.com27847de2011-02-22 20:59:41 +00001267 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1268 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001269 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001270 #endif
1271 }
1272}
1273
1274void GrContext::drawRectToRect(const GrPaint& paint,
1275 const GrRect& dstRect,
1276 const GrRect& srcRect,
1277 const GrMatrix* dstMatrix,
1278 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001279 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001280
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001281 // srcRect refers to paint's first texture
1282 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001283 drawRect(paint, dstRect, -1, dstMatrix);
1284 return;
1285 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001286
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1288
1289#if GR_STATIC_RECT_VB
1290 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001291
1292 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001293 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1294
1295 GrMatrix m;
1296
1297 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1298 0, dstRect.height(), dstRect.fTop,
1299 0, 0, GrMatrix::I()[8]);
1300 if (NULL != dstMatrix) {
1301 m.postConcat(*dstMatrix);
1302 }
1303 target->preConcatViewMatrix(m);
1304
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001305 // srcRect refers to first stage
1306 int otherStageMask = paint.getActiveStageMask() &
1307 (~(1 << GrPaint::kFirstTextureStage));
1308 if (otherStageMask) {
1309 target->preConcatSamplerMatrices(otherStageMask, m);
1310 }
1311
bsalomon@google.com27847de2011-02-22 20:59:41 +00001312 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1313 0, srcRect.height(), srcRect.fTop,
1314 0, 0, GrMatrix::I()[8]);
1315 if (NULL != srcMatrix) {
1316 m.postConcat(*srcMatrix);
1317 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001318 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001319
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001320 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1321 if (NULL == sqVB) {
1322 GrPrintf("Failed to create static rect vb.\n");
1323 return;
1324 }
1325 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1327#else
1328
1329 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001330#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001332#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001333 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1334#endif
1335
1336 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1337 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1338 srcRects[0] = &srcRect;
1339 srcMatrices[0] = srcMatrix;
1340
1341 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1342#endif
1343}
1344
1345void GrContext::drawVertices(const GrPaint& paint,
1346 GrPrimitiveType primitiveType,
1347 int vertexCount,
1348 const GrPoint positions[],
1349 const GrPoint texCoords[],
1350 const GrColor colors[],
1351 const uint16_t indices[],
1352 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001353 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001354
1355 GrDrawTarget::AutoReleaseGeometry geo;
1356
1357 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1358
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001359 bool hasTexCoords[GrPaint::kTotalStages] = {
1360 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1361 0 // remaining stages use positions
1362 };
1363
1364 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001365
1366 if (NULL != colors) {
1367 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001368 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001369 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001370
1371 if (sizeof(GrPoint) != vertexSize) {
1372 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001373 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001374 return;
1375 }
1376 int texOffsets[GrDrawTarget::kMaxTexCoords];
1377 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001378 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1379 texOffsets,
1380 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001381 void* curVertex = geo.vertices();
1382
1383 for (int i = 0; i < vertexCount; ++i) {
1384 *((GrPoint*)curVertex) = positions[i];
1385
1386 if (texOffsets[0] > 0) {
1387 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1388 }
1389 if (colorOffset > 0) {
1390 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1391 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001392 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001393 }
1394 } else {
1395 target->setVertexSourceToArray(layout, positions, vertexCount);
1396 }
1397
bsalomon@google.com91958362011-06-13 17:58:13 +00001398 // we don't currently apply offscreen AA to this path. Need improved
1399 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001400
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001401 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001402 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001403 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001404 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001405 target->drawNonIndexed(primitiveType, 0, vertexCount);
1406 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001407}
1408
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001409///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410
reed@google.com07f3ee12011-05-16 17:21:57 +00001411void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1412 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001413
bsalomon@google.com27847de2011-02-22 20:59:41 +00001414 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001415 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1416 if (NULL == pr) {
1417 GrPrintf("Unable to find path renderer compatible with path.\n");
1418 return;
1419 }
1420
bsalomon@google.comee435122011-07-01 14:57:55 +00001421 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1422 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001424 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001425 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001426
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001427 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001428
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001429 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001430 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1431 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001432 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001433 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001434 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001435 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001436 return;
1437 }
1438 }
reed@google.com70c136e2011-06-03 19:51:26 +00001439
reed@google.com07f3ee12011-05-16 17:21:57 +00001440 GrRect pathBounds = path.getBounds();
1441 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001442 if (NULL != translate) {
1443 pathBounds.offset(*translate);
1444 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001445 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001446 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001447 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001448 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001449 return;
1450 }
1451 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001452 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001453 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1454 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001455 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1456 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1457 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001458 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001459 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1460 }
1461 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001462 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001463 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001464 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1465 GrRect rect;
1466 if (clipIBounds.fTop < bound.fTop) {
1467 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1468 clipIBounds.fRight, bound.fTop);
1469 target->drawSimpleRect(rect, NULL, stageMask);
1470 }
1471 if (clipIBounds.fLeft < bound.fLeft) {
1472 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1473 bound.fLeft, bound.fBottom);
1474 target->drawSimpleRect(rect, NULL, stageMask);
1475 }
1476 if (clipIBounds.fRight > bound.fRight) {
1477 rect.setLTRB(bound.fRight, bound.fTop,
1478 clipIBounds.fRight, bound.fBottom);
1479 target->drawSimpleRect(rect, NULL, stageMask);
1480 }
1481 if (clipIBounds.fBottom > bound.fBottom) {
1482 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1483 clipIBounds.fRight, clipIBounds.fBottom);
1484 target->drawSimpleRect(rect, NULL, stageMask);
1485 }
1486 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001487 return;
1488 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001489 }
1490 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001491}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001492
bsalomon@google.com27847de2011-02-22 20:59:41 +00001493////////////////////////////////////////////////////////////////////////////////
1494
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001495void GrContext::flush(int flagsBitfield) {
1496 if (kDiscard_FlushBit & flagsBitfield) {
1497 fDrawBuffer->reset();
1498 } else {
1499 flushDrawBuffer();
1500 }
1501
1502 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001503 fGpu->forceRenderTargetFlush();
1504 }
1505}
1506
1507void GrContext::flushText() {
1508 if (kText_DrawCategory == fLastDrawCategory) {
1509 flushDrawBuffer();
1510 }
1511}
1512
1513void GrContext::flushDrawBuffer() {
1514#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001515 if (fDrawBuffer) {
1516 fDrawBuffer->playback(fGpu);
1517 fDrawBuffer->reset();
1518 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001519#endif
1520}
1521
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001522bool GrContext::readTexturePixels(GrTexture* texture,
1523 int left, int top, int width, int height,
1524 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001525 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001526
1527 // TODO: code read pixels for textures that aren't rendertargets
1528
1529 this->flush();
1530 GrRenderTarget* target = texture->asRenderTarget();
1531 if (NULL != target) {
1532 return fGpu->readPixels(target,
1533 left, top, width, height,
1534 config, buffer);
1535 } else {
1536 return false;
1537 }
1538}
1539
1540bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1541 int left, int top, int width, int height,
1542 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001543 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001544 uint32_t flushFlags = 0;
1545 if (NULL == target) {
1546 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1547 }
1548
1549 this->flush(flushFlags);
1550 return fGpu->readPixels(target,
1551 left, top, width, height,
1552 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001553}
1554
1555void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001556 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001557 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001558 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001559
1560 // TODO: when underlying api has a direct way to do this we should use it
1561 // (e.g. glDrawPixels on desktop GL).
1562
bsalomon@google.com5c638652011-07-18 19:31:59 +00001563 this->flush(true);
1564
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001565 const GrTextureDesc desc = {
1566 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001567 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001568 GrAutoScratchTexture ast(this, desc);
1569 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001570 if (NULL == texture) {
1571 return;
1572 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001573 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001574
bsalomon@google.com27847de2011-02-22 20:59:41 +00001575 GrDrawTarget::AutoStateRestore asr(fGpu);
1576
1577 GrMatrix matrix;
1578 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1579 fGpu->setViewMatrix(matrix);
1580
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001581 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001582 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1583 fGpu->setAlpha(0xFF);
1584 fGpu->setBlendFunc(kOne_BlendCoeff,
1585 kZero_BlendCoeff);
1586 fGpu->setTexture(0, texture);
1587
1588 GrSamplerState sampler;
1589 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001590 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001591 sampler.setMatrix(matrix);
1592 fGpu->setSamplerState(0, sampler);
1593
1594 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1595 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001596 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001597 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1598 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001599 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001600 return;
1601 }
1602 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1603 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1604}
1605////////////////////////////////////////////////////////////////////////////////
1606
1607void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001608
1609 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1610 int s = i + GrPaint::kFirstTextureStage;
1611 target->setTexture(s, paint.getTexture(i));
1612 target->setSamplerState(s, *paint.getTextureSampler(i));
1613 }
1614
1615 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1616
1617 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1618 int s = i + GrPaint::kFirstMaskStage;
1619 target->setTexture(s, paint.getMask(i));
1620 target->setSamplerState(s, *paint.getMaskSampler(i));
1621 }
1622
bsalomon@google.com27847de2011-02-22 20:59:41 +00001623 target->setColor(paint.fColor);
1624
1625 if (paint.fDither) {
1626 target->enableState(GrDrawTarget::kDither_StateBit);
1627 } else {
1628 target->disableState(GrDrawTarget::kDither_StateBit);
1629 }
1630 if (paint.fAntiAlias) {
1631 target->enableState(GrDrawTarget::kAntialias_StateBit);
1632 } else {
1633 target->disableState(GrDrawTarget::kAntialias_StateBit);
1634 }
1635 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001636 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001637}
1638
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001639GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001640 DrawCategory category) {
1641 if (category != fLastDrawCategory) {
1642 flushDrawBuffer();
1643 fLastDrawCategory = category;
1644 }
1645 SetPaint(paint, fGpu);
1646 GrDrawTarget* target = fGpu;
1647 switch (category) {
1648 case kText_DrawCategory:
1649#if DEFER_TEXT_RENDERING
1650 target = fDrawBuffer;
1651 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1652#else
1653 target = fGpu;
1654#endif
1655 break;
1656 case kUnbuffered_DrawCategory:
1657 target = fGpu;
1658 break;
1659 case kBuffered_DrawCategory:
1660 target = fDrawBuffer;
1661 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1662 break;
1663 }
1664 return target;
1665}
1666
bsalomon@google.com30085192011-08-19 15:42:31 +00001667GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1668 const GrPath& path,
1669 GrPathFill fill) {
1670 if (NULL == fPathRendererChain) {
1671 fPathRendererChain =
1672 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1673 }
1674 return fPathRendererChain->getPathRenderer(target, path, fill);
1675}
1676
bsalomon@google.com27847de2011-02-22 20:59:41 +00001677////////////////////////////////////////////////////////////////////////////////
1678
bsalomon@google.com27847de2011-02-22 20:59:41 +00001679void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001680 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001681 fGpu->setRenderTarget(target);
1682}
1683
1684GrRenderTarget* GrContext::getRenderTarget() {
1685 return fGpu->getRenderTarget();
1686}
1687
1688const GrRenderTarget* GrContext::getRenderTarget() const {
1689 return fGpu->getRenderTarget();
1690}
1691
1692const GrMatrix& GrContext::getMatrix() const {
1693 return fGpu->getViewMatrix();
1694}
1695
1696void GrContext::setMatrix(const GrMatrix& m) {
1697 fGpu->setViewMatrix(m);
1698}
1699
1700void GrContext::concatMatrix(const GrMatrix& m) const {
1701 fGpu->preConcatViewMatrix(m);
1702}
1703
1704static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1705 intptr_t mask = 1 << shift;
1706 if (pred) {
1707 bits |= mask;
1708 } else {
1709 bits &= ~mask;
1710 }
1711 return bits;
1712}
1713
1714void GrContext::resetStats() {
1715 fGpu->resetStats();
1716}
1717
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001718const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001719 return fGpu->getStats();
1720}
1721
1722void GrContext::printStats() const {
1723 fGpu->printStats();
1724}
1725
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001726GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001727 fGpu = gpu;
1728 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001729 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001730
bsalomon@google.com30085192011-08-19 15:42:31 +00001731 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001732
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001733 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1734 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001735 fFontCache = new GrFontCache(fGpu);
1736
1737 fLastDrawCategory = kUnbuffered_DrawCategory;
1738
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001739 fDrawBuffer = NULL;
1740 fDrawBufferVBAllocPool = NULL;
1741 fDrawBufferIBAllocPool = NULL;
1742
bsalomon@google.com205d4602011-04-25 12:43:45 +00001743 fAAFillRectIndexBuffer = NULL;
1744 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001745
1746 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1747 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1748 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1749 }
1750 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001751
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001752 this->setupDrawBuffer();
1753}
1754
1755void GrContext::setupDrawBuffer() {
1756
1757 GrAssert(NULL == fDrawBuffer);
1758 GrAssert(NULL == fDrawBufferVBAllocPool);
1759 GrAssert(NULL == fDrawBufferIBAllocPool);
1760
bsalomon@google.com27847de2011-02-22 20:59:41 +00001761#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001762 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001763 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001764 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1765 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001766 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001767 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001768 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001769 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1770
bsalomon@google.com471d4712011-08-23 15:45:25 +00001771 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1772 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001773 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001774#endif
1775
1776#if BATCH_RECT_TO_RECT
1777 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1778#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001779}
1780
bsalomon@google.com27847de2011-02-22 20:59:41 +00001781GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1782 GrDrawTarget* target;
1783#if DEFER_TEXT_RENDERING
1784 target = prepareToDraw(paint, kText_DrawCategory);
1785#else
1786 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1787#endif
1788 SetPaint(paint, target);
1789 return target;
1790}
1791
1792const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1793 return fGpu->getQuadIndexBuffer();
1794}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001795
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001796void GrContext::convolveInX(GrTexture* texture,
1797 const SkRect& rect,
1798 const float* kernel,
1799 int kernelWidth) {
1800 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1801 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1802}
1803
1804void GrContext::convolveInY(GrTexture* texture,
1805 const SkRect& rect,
1806 const float* kernel,
1807 int kernelWidth) {
1808 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1809 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1810}
1811
1812void GrContext::convolve(GrTexture* texture,
1813 const SkRect& rect,
1814 float imageIncrement[2],
1815 const float* kernel,
1816 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001817 GrDrawTarget::AutoStateRestore asr(fGpu);
1818 GrMatrix sampleM;
1819 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1820 GrSamplerState::kClamp_WrapMode,
1821 GrSamplerState::kConvolution_Filter);
1822 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001823 sampleM.setScale(GR_Scalar1 / texture->width(),
1824 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001825 sampler.setMatrix(sampleM);
1826 fGpu->setSamplerState(0, sampler);
1827 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001828 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001829 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001830 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1831}