blob: 6de31694153b9d190de9635a34996e30bbe66063 [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"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000021#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000022#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023
bsalomon@google.com91958362011-06-13 17:58:13 +000024// Using MSAA seems to be slower for some yet unknown reason.
25#define PREFER_MSAA_OFFSCREEN_AA 0
26#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000027
bsalomon@google.com27847de2011-02-22 20:59:41 +000028#define DEFER_TEXT_RENDERING 1
29
30#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000032static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
33static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000034
35static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
36static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
37
38// We are currently only batching Text and drawRectToRect, both
39// of which use the quad index buffer.
40static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
41static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
42
bsalomon@google.com05ef5102011-05-02 21:14:59 +000043GrContext* GrContext::Create(GrEngine engine,
44 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000045 GrContext* ctx = NULL;
46 GrGpu* fGpu = GrGpu::Create(engine, context3D);
47 if (NULL != fGpu) {
48 ctx = new GrContext(fGpu);
49 fGpu->unref();
50 }
51 return ctx;
52}
53
54GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000055 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000056}
57
58GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000059 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000060 delete fTextureCache;
61 delete fFontCache;
62 delete fDrawBuffer;
63 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000064 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000065
bsalomon@google.com205d4602011-04-25 12:43:45 +000066 GrSafeUnref(fAAFillRectIndexBuffer);
67 GrSafeUnref(fAAStrokeRectIndexBuffer);
68 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000069 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000070}
71
bsalomon@google.com8fe72472011-03-30 21:26:44 +000072void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000073 contextDestroyed();
74 this->setupDrawBuffer();
75}
76
77void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000078 // abandon first to so destructors
79 // don't try to free the resources in the API.
80 fGpu->abandonResources();
81
bsalomon@google.com30085192011-08-19 15:42:31 +000082 // a path renderer may be holding onto resources that
83 // are now unusable
84 GrSafeSetNull(fPathRendererChain);
85
bsalomon@google.com8fe72472011-03-30 21:26:44 +000086 delete fDrawBuffer;
87 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000088
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBufferVBAllocPool;
90 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferIBAllocPool;
93 fDrawBufferIBAllocPool = NULL;
94
bsalomon@google.com205d4602011-04-25 12:43:45 +000095 GrSafeSetNull(fAAFillRectIndexBuffer);
96 GrSafeSetNull(fAAStrokeRectIndexBuffer);
97
bsalomon@google.com8fe72472011-03-30 21:26:44 +000098 fTextureCache->removeAll();
99 fFontCache->freeAll();
100 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101}
102
103void GrContext::resetContext() {
104 fGpu->markContextDirty();
105}
106
107void GrContext::freeGpuResources() {
108 this->flush();
109 fTextureCache->removeAll();
110 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000111 // a path renderer may be holding onto resources
112 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000113}
114
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000115////////////////////////////////////////////////////////////////////////////////
116
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000117int GrContext::PaintStageVertexLayoutBits(
118 const GrPaint& paint,
119 const bool hasTexCoords[GrPaint::kTotalStages]) {
120 int stageMask = paint.getActiveStageMask();
121 int layout = 0;
122 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
123 if ((1 << i) & stageMask) {
124 if (NULL != hasTexCoords && hasTexCoords[i]) {
125 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
126 } else {
127 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
128 }
129 }
130 }
131 return layout;
132}
133
134
135////////////////////////////////////////////////////////////////////////////////
136
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000137enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000138 // flags for textures
139 kNPOTBit = 0x1,
140 kFilterBit = 0x2,
141 kScratchBit = 0x4,
142
143 // resource type
144 kTextureBit = 0x8,
145 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000146};
147
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000148GrTexture* GrContext::TextureCacheEntry::texture() const {
149 if (NULL == fEntry) {
150 return NULL;
151 } else {
152 return (GrTexture*) fEntry->resource();
153 }
154}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000155
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000156namespace {
157// returns true if this is a "special" texture because of gpu NPOT limitations
158bool gen_texture_key_values(const GrGpu* gpu,
159 const GrSamplerState& sampler,
160 GrContext::TextureKey clientKey,
161 int width,
162 int height,
163 bool scratch,
164 uint32_t v[4]) {
165 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
166 // we assume we only need 16 bits of width and height
167 // assert that texture creation will fail anyway if this assumption
168 // would cause key collisions.
169 GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
170 v[0] = clientKey & 0xffffffffUL;
171 v[1] = (clientKey >> 32) & 0xffffffffUL;
172 v[2] = width | (height << 16);
173
174 v[3] = 0;
175 if (!gpu->npotTextureTileSupport()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000176 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
177
178 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
179 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
180
181 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000182 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000183 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000184 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000185 }
186 }
187 }
188
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000189 if (scratch) {
190 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000191 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000192
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000193 v[3] |= kTextureBit;
194
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000195 return v[3] & kNPOTBit;
196}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197
198// we should never have more than one stencil buffer with same combo of
199// (width,height,samplecount)
200void gen_stencil_key_values(int width, int height,
201 int sampleCnt, uint32_t v[4]) {
202 v[0] = width;
203 v[1] = height;
204 v[2] = sampleCnt;
205 v[3] = kStencilBufferBit;
206}
207
208void gen_stencil_key_values(const GrStencilBuffer* sb,
209 uint32_t v[4]) {
210 gen_stencil_key_values(sb->width(), sb->height(),
211 sb->numSamples(), v);
212}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000213}
214
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000215GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
216 int width,
217 int height,
218 const GrSamplerState& sampler) {
219 uint32_t v[4];
220 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
221 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000222 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
223 GrResourceCache::kNested_LockType));
224}
225
226GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
227 uint32_t v[4];
228 gen_stencil_key_values(sb, v);
229 GrResourceKey resourceKey(v);
230 return fTextureCache->createAndLock(resourceKey, sb);
231}
232
233GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
234 int sampleCnt) {
235 uint32_t v[4];
236 gen_stencil_key_values(width, height, sampleCnt, v);
237 GrResourceKey resourceKey(v);
238 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
239 GrResourceCache::kSingle_LockType);
240 if (NULL != entry) {
241 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
242 return sb;
243 } else {
244 return NULL;
245 }
246}
247
248void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
249 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000250}
251
252static void stretchImage(void* dst,
253 int dstW,
254 int dstH,
255 void* src,
256 int srcW,
257 int srcH,
258 int bpp) {
259 GrFixed dx = (srcW << 16) / dstW;
260 GrFixed dy = (srcH << 16) / dstH;
261
262 GrFixed y = dy >> 1;
263
264 int dstXLimit = dstW*bpp;
265 for (int j = 0; j < dstH; ++j) {
266 GrFixed x = dx >> 1;
267 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
268 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
269 for (int i = 0; i < dstXLimit; i += bpp) {
270 memcpy((uint8_t*) dstRow + i,
271 (uint8_t*) srcRow + (x>>16)*bpp,
272 bpp);
273 x += dx;
274 }
275 y += dy;
276 }
277}
278
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000279GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000280 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000281 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000282 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000283 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000284
285#if GR_DUMP_TEXTURE_UPLOAD
286 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
287#endif
288
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000289 TextureCacheEntry entry;
290 uint32_t v[4];
291 bool special = gen_texture_key_values(fGpu, sampler, key,
292 desc.fWidth, desc.fHeight, false, v);
293 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000294
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000295 if (special) {
296 TextureCacheEntry clampEntry =
297 findAndLockTexture(key, desc.fWidth, desc.fHeight,
298 GrSamplerState::ClampNoFilter());
299
300 if (NULL == clampEntry.texture()) {
301 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000302 GrSamplerState::ClampNoFilter(),
303 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000304 GrAssert(NULL != clampEntry.texture());
305 if (NULL == clampEntry.texture()) {
306 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000307 }
308 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000309 GrTextureDesc rtDesc = desc;
310 rtDesc.fFlags = rtDesc.fFlags |
311 kRenderTarget_GrTextureFlagBit |
312 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000313 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
314 fGpu->minRenderTargetWidth()));
315 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
316 fGpu->minRenderTargetHeight()));
317
318 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
319
320 if (NULL != texture) {
321 GrDrawTarget::AutoStateRestore asr(fGpu);
322 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000323 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000324 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000325 fGpu->setViewMatrix(GrMatrix::I());
326 fGpu->setAlpha(0xff);
327 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
328 fGpu->disableState(GrDrawTarget::kDither_StateBit |
329 GrDrawTarget::kClip_StateBit |
330 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000331 GrSamplerState::Filter filter;
332 // if filtering is not desired then we want to ensure all
333 // texels in the resampled image are copies of texels from
334 // the original.
335 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
336 filter = GrSamplerState::kNearest_Filter;
337 } else {
338 filter = GrSamplerState::kBilinear_Filter;
339 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000340 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
341 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000342 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000343 fGpu->setSamplerState(0, stretchSampler);
344
345 static const GrVertexLayout layout =
346 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
347 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
348
349 if (arg.succeeded()) {
350 GrPoint* verts = (GrPoint*) arg.vertices();
351 verts[0].setIRectFan(0, 0,
352 texture->width(),
353 texture->height(),
354 2*sizeof(GrPoint));
355 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
356 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
357 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000358 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000359 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000360 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000361 } else {
362 // TODO: Our CPU stretch doesn't filter. But we create separate
363 // stretched textures when the sampler state is either filtered or
364 // not. Either implement filtered stretch blit on CPU or just create
365 // one when FBO case fails.
366
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000367 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000368 // no longer need to clamp at min RT size.
369 rtDesc.fWidth = GrNextPow2(desc.fWidth);
370 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000371 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000372 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000373 rtDesc.fWidth *
374 rtDesc.fHeight);
375 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
376 srcData, desc.fWidth, desc.fHeight, bpp);
377
378 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
379
380 GrTexture* texture = fGpu->createTexture(rtDesc,
381 stretchedPixels.get(),
382 stretchedRowBytes);
383 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000384 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000385 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000386 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000387
388 } else {
389 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
390 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000391 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000392 }
393 }
394 return entry;
395}
396
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000397namespace {
398inline void gen_scratch_tex_key_values(const GrGpu* gpu,
399 const GrTextureDesc& desc,
400 uint32_t v[4]) {
401 // Instead of a client-provided key of the texture contents
402 // we create a key of from the descriptor.
403 GrContext::TextureKey descKey = desc.fAALevel |
404 (desc.fFlags << 8) |
405 ((uint64_t) desc.fFormat << 32);
406 // this code path isn't friendly to tiling with NPOT restricitons
407 // We just pass ClampNoFilter()
408 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
409 desc.fWidth, desc.fHeight, true, v);
410}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000411}
412
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000413GrContext::TextureCacheEntry GrContext::lockScratchTexture(
414 const GrTextureDesc& inDesc,
415 ScratchTexMatch match) {
416
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000417 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000418 if (kExact_ScratchTexMatch != match) {
419 // bin by pow2 with a reasonable min
420 static const int MIN_SIZE = 256;
421 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
422 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
423 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000424
425 uint32_t p0 = desc.fFormat;
426 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
427
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000428 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000429 int origWidth = desc.fWidth;
430 int origHeight = desc.fHeight;
431 bool doubledW = false;
432 bool doubledH = false;
433
434 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000435 uint32_t v[4];
436 gen_scratch_tex_key_values(fGpu, desc, v);
437 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000438 entry = fTextureCache->findAndLock(key,
439 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000440 // if we miss, relax the fit of the flags...
441 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000442 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000443 break;
444 }
445 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
446 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
447 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
448 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
449 } else if (!doubledW) {
450 desc.fFlags = inDesc.fFlags;
451 desc.fWidth *= 2;
452 doubledW = true;
453 } else if (!doubledH) {
454 desc.fFlags = inDesc.fFlags;
455 desc.fWidth = origWidth;
456 desc.fHeight *= 2;
457 doubledH = true;
458 } else {
459 break;
460 }
461
462 } while (true);
463
464 if (NULL == entry) {
465 desc.fFlags = inDesc.fFlags;
466 desc.fWidth = origWidth;
467 desc.fHeight = origHeight;
468 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
469 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000470 uint32_t v[4];
471 gen_scratch_tex_key_values(fGpu, desc, v);
472 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000473 entry = fTextureCache->createAndLock(key, texture);
474 }
475 }
476
477 // If the caller gives us the same desc/sampler twice we don't want
478 // to return the same texture the second time (unless it was previously
479 // released). So we detach the entry from the cache and reattach at release.
480 if (NULL != entry) {
481 fTextureCache->detach(entry);
482 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000483 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000484}
485
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000486void GrContext::unlockTexture(TextureCacheEntry entry) {
487 // If this is a scratch texture we detached it from the cache
488 // while it was locked (to avoid two callers simultaneously getting
489 // the same texture).
490 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
491 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000492 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000493 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000494 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000495}
496
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000497GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000498 void* srcData,
499 size_t rowBytes) {
500 return fGpu->createTexture(desc, srcData, rowBytes);
501}
502
503void GrContext::getTextureCacheLimits(int* maxTextures,
504 size_t* maxTextureBytes) const {
505 fTextureCache->getLimits(maxTextures, maxTextureBytes);
506}
507
508void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
509 fTextureCache->setLimits(maxTextures, maxTextureBytes);
510}
511
bsalomon@google.com91958362011-06-13 17:58:13 +0000512int GrContext::getMaxTextureSize() const {
513 return fGpu->maxTextureSize();
514}
515
516int GrContext::getMaxRenderTargetSize() const {
517 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000518}
519
520///////////////////////////////////////////////////////////////////////////////
521
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000522GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
523 // validate flags here so that GrGpu subclasses don't have to check
524 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
525 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000526 return NULL;
527 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000528 if (desc.fSampleCnt &&
529 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000530 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000531 }
532 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
533 desc.fSampleCnt &&
534 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
535 return NULL;
536 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000537 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000538}
539
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000540///////////////////////////////////////////////////////////////////////////////
541
bsalomon@google.com27847de2011-02-22 20:59:41 +0000542bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000543 int width, int height) const {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000544 if (!fGpu->supports8BitPalette()) {
545 return false;
546 }
547
548
549 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
550
551 if (!isPow2) {
552 if (!fGpu->npotTextureSupport()) {
553 return false;
554 }
555
556 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
557 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
558 if (tiled && !fGpu->npotTextureTileSupport()) {
559 return false;
560 }
561 }
562 return true;
563}
564
565////////////////////////////////////////////////////////////////////////////////
566
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000567const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
568
bsalomon@google.com27847de2011-02-22 20:59:41 +0000569void GrContext::setClip(const GrClip& clip) {
570 fGpu->setClip(clip);
571 fGpu->enableState(GrDrawTarget::kClip_StateBit);
572}
573
574void GrContext::setClip(const GrIRect& rect) {
575 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000576 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577 fGpu->setClip(clip);
578}
579
580////////////////////////////////////////////////////////////////////////////////
581
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000582void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000583 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000584 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000585}
586
587void GrContext::drawPaint(const GrPaint& paint) {
588 // set rect to be big enough to fill the space, but not super-huge, so we
589 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000590 GrRect r;
591 r.setLTRB(0, 0,
592 GrIntToScalar(getRenderTarget()->width()),
593 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000594 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000595 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000596 SkTLazy<GrPaint> tmpPaint;
597 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000598 // We attempt to map r by the inverse matrix and draw that. mapRect will
599 // map the four corners and bound them with a new rect. This will not
600 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000601 if (!this->getMatrix().hasPerspective()) {
602 if (!fGpu->getViewInverse(&inverse)) {
603 GrPrintf("Could not invert matrix");
604 return;
605 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000606 inverse.mapRect(&r);
607 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000608 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
609 if (!fGpu->getViewInverse(&inverse)) {
610 GrPrintf("Could not invert matrix");
611 return;
612 }
613 tmpPaint.set(paint);
614 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
615 p = tmpPaint.get();
616 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000617 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000618 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000619 // by definition this fills the entire clip, no need for AA
620 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000621 if (!tmpPaint.isValid()) {
622 tmpPaint.set(paint);
623 p = tmpPaint.get();
624 }
625 GrAssert(p == tmpPaint.get());
626 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000627 }
628 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000629}
630
bsalomon@google.com205d4602011-04-25 12:43:45 +0000631////////////////////////////////////////////////////////////////////////////////
632
bsalomon@google.com91958362011-06-13 17:58:13 +0000633struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000634 enum Downsample {
635 k4x4TwoPass_Downsample,
636 k4x4SinglePass_Downsample,
637 kFSAA_Downsample
638 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000639 int fTileSizeX;
640 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000641 int fTileCountX;
642 int fTileCountY;
643 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000644 GrAutoScratchTexture fOffscreen0;
645 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000646 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000647 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000648};
649
bsalomon@google.com471d4712011-08-23 15:45:25 +0000650bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000651 const GrPaint& paint,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000652 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000653#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000654 return false;
655#else
656 if (!paint.fAntiAlias) {
657 return false;
658 }
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000659 // Line primitves are always rasterized as 1 pixel wide.
660 // Super-sampling would make them too thin but MSAA would be OK.
661 if (isHairLines &&
662 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA())) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000663 return false;
664 }
665 if (target->getRenderTarget()->isMultisampled()) {
666 return false;
667 }
668 // we have to be sure that the blend equation is expressible
669 // as simple src / dst coeffecients when the source
670 // is already modulated by the coverage fraction.
671 // We could use dual-source blending to get the correct per-pixel
672 // dst coeffecient for the remaining cases.
673 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
674 kOne_BlendCoeff != paint.fDstBlendCoeff &&
675 kISA_BlendCoeff != paint.fDstBlendCoeff) {
676 return false;
677 }
678 return true;
679#endif
680}
681
bsalomon@google.com91958362011-06-13 17:58:13 +0000682bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000683 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000684 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000685 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000686 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000687
688 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000689
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000690 GrAssert(NULL == record->fOffscreen0.texture());
691 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000692 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000693
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000694 int boundW = boundRect.width();
695 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000696
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000697 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000698
699 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
700 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
701
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000702 if (requireStencil) {
703 desc.fFlags = kRenderTarget_GrTextureFlagBit;
704 } else {
705 desc.fFlags = kRenderTarget_GrTextureFlagBit |
706 kNoStencil_GrTextureFlagBit;
707 }
708
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000709 desc.fFormat = kRGBA_8888_GrPixelConfig;
710
bsalomon@google.com91958362011-06-13 17:58:13 +0000711 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000712 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000713 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000714 desc.fAALevel = kMed_GrAALevel;
715 } else {
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000716 record->fDownsample = (fGpu->supportsShaders()) ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000717 OffscreenRecord::k4x4SinglePass_Downsample :
718 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000719 record->fScale = OFFSCREEN_SSAA_SCALE;
720 // both downsample paths assume this
721 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000722 desc.fAALevel = kNone_GrAALevel;
723 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000724
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000725 desc.fWidth *= record->fScale;
726 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000727 record->fOffscreen0.set(this, desc);
728 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729 return false;
730 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000731 // the approximate lookup might have given us some slop space, might as well
732 // use it when computing the tiles size.
733 // these are scale values, will adjust after considering
734 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000735 record->fTileSizeX = record->fOffscreen0.texture()->width();
736 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000737
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000738 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000739 desc.fWidth /= 2;
740 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000741 record->fOffscreen1.set(this, desc);
742 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000743 return false;
744 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000745 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000746 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000747 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000748 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000749 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000750 record->fTileSizeX /= record->fScale;
751 record->fTileSizeY /= record->fScale;
752
753 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
754 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
755
tomhudson@google.com237a4612011-07-19 15:44:00 +0000756 record->fClip = target->getClip();
757
bsalomon@google.com91958362011-06-13 17:58:13 +0000758 target->saveCurrentDrawState(&record->fSavedState);
759 return true;
760}
761
762void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
763 const GrIRect& boundRect,
764 int tileX, int tileY,
765 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000766
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000767 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000769
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000770 GrPaint tempPaint;
771 tempPaint.reset();
772 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000773 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000774
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000775 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000776 int left = boundRect.fLeft + tileX * record->fTileSizeX;
777 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000778 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000779 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000780 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000781 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000782 target->postConcatViewMatrix(scaleM);
783
bsalomon@google.com91958362011-06-13 17:58:13 +0000784 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000785 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000786 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000787 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000788 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
789 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000790 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000791#if 0
792 // visualize tile boundaries by setting edges of offscreen to white
793 // and interior to tranparent. black.
794 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795
bsalomon@google.com91958362011-06-13 17:58:13 +0000796 static const int gOffset = 2;
797 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
798 record->fScale * w - gOffset,
799 record->fScale * h - gOffset);
800 target->clear(&clear2, 0x0);
801#else
802 target->clear(&clear, 0x0);
803#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000804}
805
bsalomon@google.com91958362011-06-13 17:58:13 +0000806void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000807 const GrPaint& paint,
808 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000809 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000810 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000811 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000812 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000813 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000814 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000815 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
816 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000817 tileRect.fRight = (tileX == record->fTileCountX-1) ?
818 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000819 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000820 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
821 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000822 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000823
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000824 GrSamplerState::Filter filter;
825 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
826 filter = GrSamplerState::k4x4Downsample_Filter;
827 } else {
828 filter = GrSamplerState::kBilinear_Filter;
829 }
830
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000831 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000832 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000833 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000834
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000835 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000836 int scale;
837
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000838 enum {
839 kOffscreenStage = GrPaint::kTotalStages,
840 };
841
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000842 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000843 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000844 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000845 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000846
847 // Do 2x2 downsample from first to second
848 target->setTexture(kOffscreenStage, src);
849 target->setRenderTarget(dst);
850 target->setViewMatrix(GrMatrix::I());
851 sampleM.setScale(scale * GR_Scalar1 / src->width(),
852 scale * GR_Scalar1 / src->height());
853 sampler.setMatrix(sampleM);
854 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000855 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
856 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000857 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
858
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000859 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000860 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000861 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000862 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000863 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000864 } else {
865 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
866 record->fDownsample);
867 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000868 }
869
bsalomon@google.com91958362011-06-13 17:58:13 +0000870 // setup for draw back to main RT, we use the original
871 // draw state setup by the caller plus an additional coverage
872 // stage to handle the AA resolve. Also, we use an identity
873 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000874 int stageMask = paint.getActiveStageMask();
875
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000876 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000877 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000878
879 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000880 GrMatrix invVM;
881 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000882 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000883 }
884 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000885 // This is important when tiling, otherwise second tile's
886 // pass 1 view matrix will be incorrect.
887 GrDrawTarget::AutoViewMatrixRestore avmr(target);
888
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000889 target->setViewMatrix(GrMatrix::I());
890
891 target->setTexture(kOffscreenStage, src);
892 sampleM.setScale(scale * GR_Scalar1 / src->width(),
893 scale * GR_Scalar1 / src->height());
894 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000895 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000896 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000897 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000898
reed@google.com20efde72011-05-09 17:00:02 +0000899 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000900 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000901 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000902 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000903}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000904
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000905void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
906 GrPathRenderer* pr,
907 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000908 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000909}
910
911////////////////////////////////////////////////////////////////////////////////
912
bsalomon@google.com27847de2011-02-22 20:59:41 +0000913/* create a triangle strip that strokes the specified triangle. There are 8
914 unique vertices, but we repreat the last 2 to close up. Alternatively we
915 could use an indices array, and then only send 8 verts, but not sure that
916 would be faster.
917 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000918static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000919 GrScalar width) {
920 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000921 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000922
923 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
924 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
925 verts[2].set(rect.fRight - rad, rect.fTop + rad);
926 verts[3].set(rect.fRight + rad, rect.fTop - rad);
927 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
928 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
929 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
930 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
931 verts[8] = verts[0];
932 verts[9] = verts[1];
933}
934
bsalomon@google.com205d4602011-04-25 12:43:45 +0000935static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000936 // FIXME: This was copied from SkGpuDevice, seems like
937 // we should have already smeared a in caller if that
938 // is what is desired.
939 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000940 unsigned a = GrColorUnpackA(paint.fColor);
941 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000942 } else {
943 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000944 }
945}
946
947static void setInsetFan(GrPoint* pts, size_t stride,
948 const GrRect& r, GrScalar dx, GrScalar dy) {
949 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
950}
951
952static const uint16_t gFillAARectIdx[] = {
953 0, 1, 5, 5, 4, 0,
954 1, 2, 6, 6, 5, 1,
955 2, 3, 7, 7, 6, 2,
956 3, 0, 4, 4, 7, 3,
957 4, 5, 6, 6, 7, 4,
958};
959
960int GrContext::aaFillRectIndexCount() const {
961 return GR_ARRAY_COUNT(gFillAARectIdx);
962}
963
964GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
965 if (NULL == fAAFillRectIndexBuffer) {
966 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
967 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000968 if (NULL != fAAFillRectIndexBuffer) {
969 #if GR_DEBUG
970 bool updated =
971 #endif
972 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
973 sizeof(gFillAARectIdx));
974 GR_DEBUGASSERT(updated);
975 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000976 }
977 return fAAFillRectIndexBuffer;
978}
979
980static const uint16_t gStrokeAARectIdx[] = {
981 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
982 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
983 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
984 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
985
986 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
987 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
988 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
989 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
990
991 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
992 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
993 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
994 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
995};
996
997int GrContext::aaStrokeRectIndexCount() const {
998 return GR_ARRAY_COUNT(gStrokeAARectIdx);
999}
1000
1001GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1002 if (NULL == fAAStrokeRectIndexBuffer) {
1003 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1004 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001005 if (NULL != fAAStrokeRectIndexBuffer) {
1006 #if GR_DEBUG
1007 bool updated =
1008 #endif
1009 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1010 sizeof(gStrokeAARectIdx));
1011 GR_DEBUGASSERT(updated);
1012 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001013 }
1014 return fAAStrokeRectIndexBuffer;
1015}
1016
1017void GrContext::fillAARect(GrDrawTarget* target,
1018 const GrPaint& paint,
1019 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001020 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1021 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001022
1023 size_t vsize = GrDrawTarget::VertexSize(layout);
1024
1025 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001026 if (!geo.succeeded()) {
1027 GrPrintf("Failed to get space for vertices!\n");
1028 return;
1029 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001030 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1031 if (NULL == indexBuffer) {
1032 GrPrintf("Failed to create index buffer!\n");
1033 return;
1034 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001035
1036 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1037
1038 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1039 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1040
1041 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1042 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1043
1044 verts += sizeof(GrPoint);
1045 for (int i = 0; i < 4; ++i) {
1046 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1047 }
1048
1049 GrColor innerColor = getColorForMesh(paint);
1050 verts += 4 * vsize;
1051 for (int i = 0; i < 4; ++i) {
1052 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1053 }
1054
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001055 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001056
1057 target->drawIndexed(kTriangles_PrimitiveType, 0,
1058 0, 8, this->aaFillRectIndexCount());
1059}
1060
1061void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1062 const GrRect& devRect, const GrVec& devStrokeSize) {
1063 const GrScalar& dx = devStrokeSize.fX;
1064 const GrScalar& dy = devStrokeSize.fY;
1065 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1066 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1067
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001068 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1069 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001070
1071 GrScalar spare;
1072 {
1073 GrScalar w = devRect.width() - dx;
1074 GrScalar h = devRect.height() - dy;
1075 spare = GrMin(w, h);
1076 }
1077
1078 if (spare <= 0) {
1079 GrRect r(devRect);
1080 r.inset(-rx, -ry);
1081 fillAARect(target, paint, r);
1082 return;
1083 }
1084
1085 size_t vsize = GrDrawTarget::VertexSize(layout);
1086
1087 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001088 if (!geo.succeeded()) {
1089 GrPrintf("Failed to get space for vertices!\n");
1090 return;
1091 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001092 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1093 if (NULL == indexBuffer) {
1094 GrPrintf("Failed to create index buffer!\n");
1095 return;
1096 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001097
1098 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1099
1100 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1101 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1102 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1103 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1104
1105 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1106 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1107 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1108 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1109
1110 verts += sizeof(GrPoint);
1111 for (int i = 0; i < 4; ++i) {
1112 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1113 }
1114
1115 GrColor innerColor = getColorForMesh(paint);
1116 verts += 4 * vsize;
1117 for (int i = 0; i < 8; ++i) {
1118 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1119 }
1120
1121 verts += 8 * vsize;
1122 for (int i = 0; i < 8; ++i) {
1123 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1124 }
1125
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001126 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001127 target->drawIndexed(kTriangles_PrimitiveType,
1128 0, 0, 16, aaStrokeRectIndexCount());
1129}
1130
reed@google.com20efde72011-05-09 17:00:02 +00001131/**
1132 * Returns true if the rects edges are integer-aligned.
1133 */
1134static bool isIRect(const GrRect& r) {
1135 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1136 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1137}
1138
bsalomon@google.com205d4602011-04-25 12:43:45 +00001139static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001140 const GrPaint& paint,
1141 const GrRect& rect,
1142 GrScalar width,
1143 const GrMatrix* matrix,
1144 GrMatrix* combinedMatrix,
1145 GrRect* devRect) {
1146 // we use a simple alpha ramp to do aa on axis-aligned rects
1147 // do AA with alpha ramp if the caller requested AA, the rect
1148 // will be axis-aligned,the render target is not
1149 // multisampled, and the rect won't land on integer coords.
1150
1151 if (!paint.fAntiAlias) {
1152 return false;
1153 }
1154
1155 if (target->getRenderTarget()->isMultisampled()) {
1156 return false;
1157 }
1158
bsalomon@google.com471d4712011-08-23 15:45:25 +00001159 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001160 return false;
1161 }
1162
1163 if (!target->getViewMatrix().preservesAxisAlignment()) {
1164 return false;
1165 }
1166
1167 if (NULL != matrix &&
1168 !matrix->preservesAxisAlignment()) {
1169 return false;
1170 }
1171
1172 *combinedMatrix = target->getViewMatrix();
1173 if (NULL != matrix) {
1174 combinedMatrix->preConcat(*matrix);
1175 GrAssert(combinedMatrix->preservesAxisAlignment());
1176 }
1177
1178 combinedMatrix->mapRect(devRect, rect);
1179 devRect->sort();
1180
1181 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001182 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001183 } else {
1184 return true;
1185 }
1186}
1187
bsalomon@google.com27847de2011-02-22 20:59:41 +00001188void GrContext::drawRect(const GrPaint& paint,
1189 const GrRect& rect,
1190 GrScalar width,
1191 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001192 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001193
1194 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001195 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196
bsalomon@google.com205d4602011-04-25 12:43:45 +00001197 GrRect devRect = rect;
1198 GrMatrix combinedMatrix;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001199 bool doAA = apply_aa_to_rect(target, paint, rect, width, matrix,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001200 &combinedMatrix, &devRect);
1201
1202 if (doAA) {
1203 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001204 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001205 GrMatrix inv;
1206 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001207 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001208 }
1209 }
1210 target->setViewMatrix(GrMatrix::I());
1211 if (width >= 0) {
1212 GrVec strokeSize;;
1213 if (width > 0) {
1214 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001215 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001216 strokeSize.setAbs(strokeSize);
1217 } else {
1218 strokeSize.set(GR_Scalar1, GR_Scalar1);
1219 }
1220 strokeAARect(target, paint, devRect, strokeSize);
1221 } else {
1222 fillAARect(target, paint, devRect);
1223 }
1224 return;
1225 }
1226
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227 if (width >= 0) {
1228 // TODO: consider making static vertex buffers for these cases.
1229 // Hairline could be done by just adding closing vertex to
1230 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001231 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1232
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233 static const int worstCaseVertCount = 10;
1234 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1235
1236 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001237 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001238 return;
1239 }
1240
1241 GrPrimitiveType primType;
1242 int vertCount;
1243 GrPoint* vertex = geo.positions();
1244
1245 if (width > 0) {
1246 vertCount = 10;
1247 primType = kTriangleStrip_PrimitiveType;
1248 setStrokeRectStrip(vertex, rect, width);
1249 } else {
1250 // hairline
1251 vertCount = 5;
1252 primType = kLineStrip_PrimitiveType;
1253 vertex[0].set(rect.fLeft, rect.fTop);
1254 vertex[1].set(rect.fRight, rect.fTop);
1255 vertex[2].set(rect.fRight, rect.fBottom);
1256 vertex[3].set(rect.fLeft, rect.fBottom);
1257 vertex[4].set(rect.fLeft, rect.fTop);
1258 }
1259
1260 GrDrawTarget::AutoViewMatrixRestore avmr;
1261 if (NULL != matrix) {
1262 avmr.set(target);
1263 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001264 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265 }
1266
1267 target->drawNonIndexed(primType, 0, vertCount);
1268 } else {
1269 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001270 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001271 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1272 if (NULL == sqVB) {
1273 GrPrintf("Failed to create static rect vb.\n");
1274 return;
1275 }
1276 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001277 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1278 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001279 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001280 0, rect.height(), rect.fTop,
1281 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001282
1283 if (NULL != matrix) {
1284 m.postConcat(*matrix);
1285 }
1286
1287 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001288 target->preConcatSamplerMatrices(stageMask, m);
1289
bsalomon@google.com27847de2011-02-22 20:59:41 +00001290 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1291 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001292 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001293 #endif
1294 }
1295}
1296
1297void GrContext::drawRectToRect(const GrPaint& paint,
1298 const GrRect& dstRect,
1299 const GrRect& srcRect,
1300 const GrMatrix* dstMatrix,
1301 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001302 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001303
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001304 // srcRect refers to paint's first texture
1305 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001306 drawRect(paint, dstRect, -1, dstMatrix);
1307 return;
1308 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001309
bsalomon@google.com27847de2011-02-22 20:59:41 +00001310 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1311
1312#if GR_STATIC_RECT_VB
1313 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001314
1315 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001316 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1317
1318 GrMatrix m;
1319
1320 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1321 0, dstRect.height(), dstRect.fTop,
1322 0, 0, GrMatrix::I()[8]);
1323 if (NULL != dstMatrix) {
1324 m.postConcat(*dstMatrix);
1325 }
1326 target->preConcatViewMatrix(m);
1327
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001328 // srcRect refers to first stage
1329 int otherStageMask = paint.getActiveStageMask() &
1330 (~(1 << GrPaint::kFirstTextureStage));
1331 if (otherStageMask) {
1332 target->preConcatSamplerMatrices(otherStageMask, m);
1333 }
1334
bsalomon@google.com27847de2011-02-22 20:59:41 +00001335 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1336 0, srcRect.height(), srcRect.fTop,
1337 0, 0, GrMatrix::I()[8]);
1338 if (NULL != srcMatrix) {
1339 m.postConcat(*srcMatrix);
1340 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001341 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001342
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001343 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1344 if (NULL == sqVB) {
1345 GrPrintf("Failed to create static rect vb.\n");
1346 return;
1347 }
1348 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001349 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1350#else
1351
1352 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001353#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001354 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001355#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001356 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1357#endif
1358
1359 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1360 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1361 srcRects[0] = &srcRect;
1362 srcMatrices[0] = srcMatrix;
1363
1364 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1365#endif
1366}
1367
1368void GrContext::drawVertices(const GrPaint& paint,
1369 GrPrimitiveType primitiveType,
1370 int vertexCount,
1371 const GrPoint positions[],
1372 const GrPoint texCoords[],
1373 const GrColor colors[],
1374 const uint16_t indices[],
1375 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001376 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377
1378 GrDrawTarget::AutoReleaseGeometry geo;
1379
1380 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1381
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001382 bool hasTexCoords[GrPaint::kTotalStages] = {
1383 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1384 0 // remaining stages use positions
1385 };
1386
1387 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001388
1389 if (NULL != colors) {
1390 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001391 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001392 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001393
1394 if (sizeof(GrPoint) != vertexSize) {
1395 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001396 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397 return;
1398 }
1399 int texOffsets[GrDrawTarget::kMaxTexCoords];
1400 int colorOffset;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001401 int edgeOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001402 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1403 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001404 &colorOffset,
1405 &edgeOffset);
1406 GrAssert(-1 == edgeOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001407 void* curVertex = geo.vertices();
1408
1409 for (int i = 0; i < vertexCount; ++i) {
1410 *((GrPoint*)curVertex) = positions[i];
1411
1412 if (texOffsets[0] > 0) {
1413 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1414 }
1415 if (colorOffset > 0) {
1416 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1417 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001418 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001419 }
1420 } else {
1421 target->setVertexSourceToArray(layout, positions, vertexCount);
1422 }
1423
bsalomon@google.com91958362011-06-13 17:58:13 +00001424 // we don't currently apply offscreen AA to this path. Need improved
1425 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001426
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001427 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001428 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001429 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001430 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001431 target->drawNonIndexed(primitiveType, 0, vertexCount);
1432 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001433}
1434
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001435///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001436
reed@google.com07f3ee12011-05-16 17:21:57 +00001437void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1438 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001439
bsalomon@google.com27847de2011-02-22 20:59:41 +00001440 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001441 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1442 if (NULL == pr) {
1443 GrPrintf("Unable to find path renderer compatible with path.\n");
1444 return;
1445 }
1446
bsalomon@google.comee435122011-07-01 14:57:55 +00001447 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1448 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001449
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001450 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001451 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001452
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001453 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001454
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001455 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001456 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1457 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001458 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001459 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001460 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001461 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001462 return;
1463 }
1464 }
reed@google.com70c136e2011-06-03 19:51:26 +00001465
reed@google.com07f3ee12011-05-16 17:21:57 +00001466 GrRect pathBounds = path.getBounds();
1467 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001468 if (NULL != translate) {
1469 pathBounds.offset(*translate);
1470 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001471 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001472 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001473 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001474 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001475 return;
1476 }
1477 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001478 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001479 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1480 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001481 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1482 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1483 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001484 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001485 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1486 }
1487 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001488 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001489 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001490 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1491 GrRect rect;
1492 if (clipIBounds.fTop < bound.fTop) {
1493 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1494 clipIBounds.fRight, bound.fTop);
1495 target->drawSimpleRect(rect, NULL, stageMask);
1496 }
1497 if (clipIBounds.fLeft < bound.fLeft) {
1498 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1499 bound.fLeft, bound.fBottom);
1500 target->drawSimpleRect(rect, NULL, stageMask);
1501 }
1502 if (clipIBounds.fRight > bound.fRight) {
1503 rect.setLTRB(bound.fRight, bound.fTop,
1504 clipIBounds.fRight, bound.fBottom);
1505 target->drawSimpleRect(rect, NULL, stageMask);
1506 }
1507 if (clipIBounds.fBottom > bound.fBottom) {
1508 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1509 clipIBounds.fRight, clipIBounds.fBottom);
1510 target->drawSimpleRect(rect, NULL, stageMask);
1511 }
1512 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001513 return;
1514 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001515 }
1516 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001517}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001518
bsalomon@google.com27847de2011-02-22 20:59:41 +00001519////////////////////////////////////////////////////////////////////////////////
1520
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001521bool GrContext::supportsShaders() const {
1522 return fGpu->supportsShaders();
1523}
1524
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001525void GrContext::flush(int flagsBitfield) {
1526 if (kDiscard_FlushBit & flagsBitfield) {
1527 fDrawBuffer->reset();
1528 } else {
1529 flushDrawBuffer();
1530 }
1531
1532 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001533 fGpu->forceRenderTargetFlush();
1534 }
1535}
1536
1537void GrContext::flushText() {
1538 if (kText_DrawCategory == fLastDrawCategory) {
1539 flushDrawBuffer();
1540 }
1541}
1542
1543void GrContext::flushDrawBuffer() {
1544#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001545 if (fDrawBuffer) {
1546 fDrawBuffer->playback(fGpu);
1547 fDrawBuffer->reset();
1548 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001549#endif
1550}
1551
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001552bool GrContext::readTexturePixels(GrTexture* texture,
1553 int left, int top, int width, int height,
1554 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001555 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001556
1557 // TODO: code read pixels for textures that aren't rendertargets
1558
1559 this->flush();
1560 GrRenderTarget* target = texture->asRenderTarget();
1561 if (NULL != target) {
1562 return fGpu->readPixels(target,
1563 left, top, width, height,
1564 config, buffer);
1565 } else {
1566 return false;
1567 }
1568}
1569
1570bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1571 int left, int top, int width, int height,
1572 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001573 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001574 uint32_t flushFlags = 0;
1575 if (NULL == target) {
1576 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1577 }
1578
1579 this->flush(flushFlags);
1580 return fGpu->readPixels(target,
1581 left, top, width, height,
1582 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001583}
1584
1585void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001586 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001587 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001588 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001589
1590 // TODO: when underlying api has a direct way to do this we should use it
1591 // (e.g. glDrawPixels on desktop GL).
1592
bsalomon@google.com5c638652011-07-18 19:31:59 +00001593 this->flush(true);
1594
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001595 const GrTextureDesc desc = {
1596 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001597 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001598 GrAutoScratchTexture ast(this, desc);
1599 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001600 if (NULL == texture) {
1601 return;
1602 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001603 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001604
bsalomon@google.com27847de2011-02-22 20:59:41 +00001605 GrDrawTarget::AutoStateRestore asr(fGpu);
1606
1607 GrMatrix matrix;
1608 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1609 fGpu->setViewMatrix(matrix);
1610
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001611 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001612 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1613 fGpu->setAlpha(0xFF);
1614 fGpu->setBlendFunc(kOne_BlendCoeff,
1615 kZero_BlendCoeff);
1616 fGpu->setTexture(0, texture);
1617
1618 GrSamplerState sampler;
1619 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001620 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001621 sampler.setMatrix(matrix);
1622 fGpu->setSamplerState(0, sampler);
1623
1624 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1625 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001626 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001627 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1628 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001629 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001630 return;
1631 }
1632 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1633 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1634}
1635////////////////////////////////////////////////////////////////////////////////
1636
1637void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001638
1639 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1640 int s = i + GrPaint::kFirstTextureStage;
1641 target->setTexture(s, paint.getTexture(i));
1642 target->setSamplerState(s, *paint.getTextureSampler(i));
1643 }
1644
1645 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1646
1647 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1648 int s = i + GrPaint::kFirstMaskStage;
1649 target->setTexture(s, paint.getMask(i));
1650 target->setSamplerState(s, *paint.getMaskSampler(i));
1651 }
1652
bsalomon@google.com27847de2011-02-22 20:59:41 +00001653 target->setColor(paint.fColor);
1654
1655 if (paint.fDither) {
1656 target->enableState(GrDrawTarget::kDither_StateBit);
1657 } else {
1658 target->disableState(GrDrawTarget::kDither_StateBit);
1659 }
1660 if (paint.fAntiAlias) {
1661 target->enableState(GrDrawTarget::kAntialias_StateBit);
1662 } else {
1663 target->disableState(GrDrawTarget::kAntialias_StateBit);
1664 }
1665 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001666 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001667}
1668
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001669GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001670 DrawCategory category) {
1671 if (category != fLastDrawCategory) {
1672 flushDrawBuffer();
1673 fLastDrawCategory = category;
1674 }
1675 SetPaint(paint, fGpu);
1676 GrDrawTarget* target = fGpu;
1677 switch (category) {
1678 case kText_DrawCategory:
1679#if DEFER_TEXT_RENDERING
1680 target = fDrawBuffer;
1681 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1682#else
1683 target = fGpu;
1684#endif
1685 break;
1686 case kUnbuffered_DrawCategory:
1687 target = fGpu;
1688 break;
1689 case kBuffered_DrawCategory:
1690 target = fDrawBuffer;
1691 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1692 break;
1693 }
1694 return target;
1695}
1696
bsalomon@google.com30085192011-08-19 15:42:31 +00001697GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1698 const GrPath& path,
1699 GrPathFill fill) {
1700 if (NULL == fPathRendererChain) {
1701 fPathRendererChain =
1702 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1703 }
1704 return fPathRendererChain->getPathRenderer(target, path, fill);
1705}
1706
bsalomon@google.com27847de2011-02-22 20:59:41 +00001707////////////////////////////////////////////////////////////////////////////////
1708
bsalomon@google.com27847de2011-02-22 20:59:41 +00001709void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001710 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001711 fGpu->setRenderTarget(target);
1712}
1713
1714GrRenderTarget* GrContext::getRenderTarget() {
1715 return fGpu->getRenderTarget();
1716}
1717
1718const GrRenderTarget* GrContext::getRenderTarget() const {
1719 return fGpu->getRenderTarget();
1720}
1721
1722const GrMatrix& GrContext::getMatrix() const {
1723 return fGpu->getViewMatrix();
1724}
1725
1726void GrContext::setMatrix(const GrMatrix& m) {
1727 fGpu->setViewMatrix(m);
1728}
1729
1730void GrContext::concatMatrix(const GrMatrix& m) const {
1731 fGpu->preConcatViewMatrix(m);
1732}
1733
1734static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1735 intptr_t mask = 1 << shift;
1736 if (pred) {
1737 bits |= mask;
1738 } else {
1739 bits &= ~mask;
1740 }
1741 return bits;
1742}
1743
1744void GrContext::resetStats() {
1745 fGpu->resetStats();
1746}
1747
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001748const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001749 return fGpu->getStats();
1750}
1751
1752void GrContext::printStats() const {
1753 fGpu->printStats();
1754}
1755
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001756GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001757 fGpu = gpu;
1758 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001759 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001760
bsalomon@google.com30085192011-08-19 15:42:31 +00001761 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001762
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001763 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1764 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001765 fFontCache = new GrFontCache(fGpu);
1766
1767 fLastDrawCategory = kUnbuffered_DrawCategory;
1768
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001769 fDrawBuffer = NULL;
1770 fDrawBufferVBAllocPool = NULL;
1771 fDrawBufferIBAllocPool = NULL;
1772
bsalomon@google.com205d4602011-04-25 12:43:45 +00001773 fAAFillRectIndexBuffer = NULL;
1774 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001775
1776 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1777 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1778 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1779 }
1780 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001781
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001782 this->setupDrawBuffer();
1783}
1784
1785void GrContext::setupDrawBuffer() {
1786
1787 GrAssert(NULL == fDrawBuffer);
1788 GrAssert(NULL == fDrawBufferVBAllocPool);
1789 GrAssert(NULL == fDrawBufferIBAllocPool);
1790
bsalomon@google.com27847de2011-02-22 20:59:41 +00001791#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001792 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001793 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001794 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1795 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001796 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001797 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001798 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001799 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1800
bsalomon@google.com471d4712011-08-23 15:45:25 +00001801 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1802 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001803 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001804#endif
1805
1806#if BATCH_RECT_TO_RECT
1807 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1808#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001809}
1810
bsalomon@google.com27847de2011-02-22 20:59:41 +00001811GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1812 GrDrawTarget* target;
1813#if DEFER_TEXT_RENDERING
1814 target = prepareToDraw(paint, kText_DrawCategory);
1815#else
1816 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1817#endif
1818 SetPaint(paint, target);
1819 return target;
1820}
1821
1822const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1823 return fGpu->getQuadIndexBuffer();
1824}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001825
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001826void GrContext::convolveInX(GrTexture* texture,
1827 const SkRect& rect,
1828 const float* kernel,
1829 int kernelWidth) {
1830 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1831 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1832}
1833
1834void GrContext::convolveInY(GrTexture* texture,
1835 const SkRect& rect,
1836 const float* kernel,
1837 int kernelWidth) {
1838 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1839 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1840}
1841
1842void GrContext::convolve(GrTexture* texture,
1843 const SkRect& rect,
1844 float imageIncrement[2],
1845 const float* kernel,
1846 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001847 GrDrawTarget::AutoStateRestore asr(fGpu);
1848 GrMatrix sampleM;
1849 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1850 GrSamplerState::kClamp_WrapMode,
1851 GrSamplerState::kConvolution_Filter);
1852 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001853 sampleM.setScale(GR_Scalar1 / texture->width(),
1854 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001855 sampler.setMatrix(sampleM);
1856 fGpu->setSamplerState(0, sampler);
1857 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001858 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001859 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001860 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1861}