blob: 689cb57a98219d7b53725093c5e0ec01d9977fa5 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000021#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000022
bsalomon@google.com91958362011-06-13 17:58:13 +000023// Using MSAA seems to be slower for some yet unknown reason.
24#define PREFER_MSAA_OFFSCREEN_AA 0
25#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000026
bsalomon@google.com27847de2011-02-22 20:59:41 +000027#define DEFER_TEXT_RENDERING 1
28
29#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
30
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000031static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
32static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000033
34static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
35static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
36
37// We are currently only batching Text and drawRectToRect, both
38// of which use the quad index buffer.
39static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
40static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
41
bsalomon@google.com05ef5102011-05-02 21:14:59 +000042GrContext* GrContext::Create(GrEngine engine,
43 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000044 GrContext* ctx = NULL;
45 GrGpu* fGpu = GrGpu::Create(engine, context3D);
46 if (NULL != fGpu) {
47 ctx = new GrContext(fGpu);
48 fGpu->unref();
49 }
50 return ctx;
51}
52
53GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000054 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000055}
56
57GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000058 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000059 delete fTextureCache;
60 delete fFontCache;
61 delete fDrawBuffer;
62 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000063 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000064
bsalomon@google.com205d4602011-04-25 12:43:45 +000065 GrSafeUnref(fAAFillRectIndexBuffer);
66 GrSafeUnref(fAAStrokeRectIndexBuffer);
67 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000068 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000069}
70
bsalomon@google.com8fe72472011-03-30 21:26:44 +000071void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000072 contextDestroyed();
73 this->setupDrawBuffer();
74}
75
76void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000077 // abandon first to so destructors
78 // don't try to free the resources in the API.
79 fGpu->abandonResources();
80
bsalomon@google.com30085192011-08-19 15:42:31 +000081 // a path renderer may be holding onto resources that
82 // are now unusable
83 GrSafeSetNull(fPathRendererChain);
84
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBuffer;
86 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000087
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBufferVBAllocPool;
89 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferIBAllocPool;
92 fDrawBufferIBAllocPool = NULL;
93
bsalomon@google.com205d4602011-04-25 12:43:45 +000094 GrSafeSetNull(fAAFillRectIndexBuffer);
95 GrSafeSetNull(fAAStrokeRectIndexBuffer);
96
bsalomon@google.com8fe72472011-03-30 21:26:44 +000097 fTextureCache->removeAll();
98 fFontCache->freeAll();
99 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100}
101
102void GrContext::resetContext() {
103 fGpu->markContextDirty();
104}
105
106void GrContext::freeGpuResources() {
107 this->flush();
108 fTextureCache->removeAll();
109 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000110 // a path renderer may be holding onto resources
111 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000112}
113
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000114////////////////////////////////////////////////////////////////////////////////
115
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000116int GrContext::PaintStageVertexLayoutBits(
117 const GrPaint& paint,
118 const bool hasTexCoords[GrPaint::kTotalStages]) {
119 int stageMask = paint.getActiveStageMask();
120 int layout = 0;
121 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
122 if ((1 << i) & stageMask) {
123 if (NULL != hasTexCoords && hasTexCoords[i]) {
124 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
125 } else {
126 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
127 }
128 }
129 }
130 return layout;
131}
132
133
134////////////////////////////////////////////////////////////////////////////////
135
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000136enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000137 // flags for textures
138 kNPOTBit = 0x1,
139 kFilterBit = 0x2,
140 kScratchBit = 0x4,
141
142 // resource type
143 kTextureBit = 0x8,
144 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000145};
146
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000147GrTexture* GrContext::TextureCacheEntry::texture() const {
148 if (NULL == fEntry) {
149 return NULL;
150 } else {
151 return (GrTexture*) fEntry->resource();
152 }
153}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000154
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000155namespace {
156// returns true if this is a "special" texture because of gpu NPOT limitations
157bool gen_texture_key_values(const GrGpu* gpu,
158 const GrSamplerState& sampler,
159 GrContext::TextureKey clientKey,
160 int width,
161 int height,
162 bool scratch,
163 uint32_t v[4]) {
164 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
165 // we assume we only need 16 bits of width and height
166 // assert that texture creation will fail anyway if this assumption
167 // would cause key collisions.
168 GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
169 v[0] = clientKey & 0xffffffffUL;
170 v[1] = (clientKey >> 32) & 0xffffffffUL;
171 v[2] = width | (height << 16);
172
173 v[3] = 0;
174 if (!gpu->npotTextureTileSupport()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000175 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
176
177 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
178 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
179
180 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000181 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000182 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000183 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184 }
185 }
186 }
187
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 if (scratch) {
189 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000190 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000192 v[3] |= kTextureBit;
193
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194 return v[3] & kNPOTBit;
195}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000196
197// we should never have more than one stencil buffer with same combo of
198// (width,height,samplecount)
199void gen_stencil_key_values(int width, int height,
200 int sampleCnt, uint32_t v[4]) {
201 v[0] = width;
202 v[1] = height;
203 v[2] = sampleCnt;
204 v[3] = kStencilBufferBit;
205}
206
207void gen_stencil_key_values(const GrStencilBuffer* sb,
208 uint32_t v[4]) {
209 gen_stencil_key_values(sb->width(), sb->height(),
210 sb->numSamples(), v);
211}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000212}
213
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000214GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
215 int width,
216 int height,
217 const GrSamplerState& sampler) {
218 uint32_t v[4];
219 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
220 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000221 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
222 GrResourceCache::kNested_LockType));
223}
224
225GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
226 uint32_t v[4];
227 gen_stencil_key_values(sb, v);
228 GrResourceKey resourceKey(v);
229 return fTextureCache->createAndLock(resourceKey, sb);
230}
231
232GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
233 int sampleCnt) {
234 uint32_t v[4];
235 gen_stencil_key_values(width, height, sampleCnt, v);
236 GrResourceKey resourceKey(v);
237 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
238 GrResourceCache::kSingle_LockType);
239 if (NULL != entry) {
240 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
241 return sb;
242 } else {
243 return NULL;
244 }
245}
246
247void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
248 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000249}
250
251static void stretchImage(void* dst,
252 int dstW,
253 int dstH,
254 void* src,
255 int srcW,
256 int srcH,
257 int bpp) {
258 GrFixed dx = (srcW << 16) / dstW;
259 GrFixed dy = (srcH << 16) / dstH;
260
261 GrFixed y = dy >> 1;
262
263 int dstXLimit = dstW*bpp;
264 for (int j = 0; j < dstH; ++j) {
265 GrFixed x = dx >> 1;
266 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
267 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
268 for (int i = 0; i < dstXLimit; i += bpp) {
269 memcpy((uint8_t*) dstRow + i,
270 (uint8_t*) srcRow + (x>>16)*bpp,
271 bpp);
272 x += dx;
273 }
274 y += dy;
275 }
276}
277
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000278GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000279 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000280 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000281 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000282 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000283
284#if GR_DUMP_TEXTURE_UPLOAD
285 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
286#endif
287
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000288 TextureCacheEntry entry;
289 uint32_t v[4];
290 bool special = gen_texture_key_values(fGpu, sampler, key,
291 desc.fWidth, desc.fHeight, false, v);
292 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000293
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000294 if (special) {
295 TextureCacheEntry clampEntry =
296 findAndLockTexture(key, desc.fWidth, desc.fHeight,
297 GrSamplerState::ClampNoFilter());
298
299 if (NULL == clampEntry.texture()) {
300 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000301 GrSamplerState::ClampNoFilter(),
302 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000303 GrAssert(NULL != clampEntry.texture());
304 if (NULL == clampEntry.texture()) {
305 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000306 }
307 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000308 GrTextureDesc rtDesc = desc;
309 rtDesc.fFlags = rtDesc.fFlags |
310 kRenderTarget_GrTextureFlagBit |
311 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000312 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
313 fGpu->minRenderTargetWidth()));
314 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
315 fGpu->minRenderTargetHeight()));
316
317 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
318
319 if (NULL != texture) {
320 GrDrawTarget::AutoStateRestore asr(fGpu);
321 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000322 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000323 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000324 fGpu->setViewMatrix(GrMatrix::I());
325 fGpu->setAlpha(0xff);
326 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
327 fGpu->disableState(GrDrawTarget::kDither_StateBit |
328 GrDrawTarget::kClip_StateBit |
329 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000330 GrSamplerState::Filter filter;
331 // if filtering is not desired then we want to ensure all
332 // texels in the resampled image are copies of texels from
333 // the original.
334 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
335 filter = GrSamplerState::kNearest_Filter;
336 } else {
337 filter = GrSamplerState::kBilinear_Filter;
338 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000339 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
340 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000341 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000342 fGpu->setSamplerState(0, stretchSampler);
343
344 static const GrVertexLayout layout =
345 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
346 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
347
348 if (arg.succeeded()) {
349 GrPoint* verts = (GrPoint*) arg.vertices();
350 verts[0].setIRectFan(0, 0,
351 texture->width(),
352 texture->height(),
353 2*sizeof(GrPoint));
354 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
355 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
356 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000357 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000358 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000359 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000360 } else {
361 // TODO: Our CPU stretch doesn't filter. But we create separate
362 // stretched textures when the sampler state is either filtered or
363 // not. Either implement filtered stretch blit on CPU or just create
364 // one when FBO case fails.
365
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000366 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000367 // no longer need to clamp at min RT size.
368 rtDesc.fWidth = GrNextPow2(desc.fWidth);
369 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000370 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000371 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000372 rtDesc.fWidth *
373 rtDesc.fHeight);
374 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
375 srcData, desc.fWidth, desc.fHeight, bpp);
376
377 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
378
379 GrTexture* texture = fGpu->createTexture(rtDesc,
380 stretchedPixels.get(),
381 stretchedRowBytes);
382 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000383 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000384 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000385 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000386
387 } else {
388 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
389 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000390 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 }
392 }
393 return entry;
394}
395
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000396namespace {
397inline void gen_scratch_tex_key_values(const GrGpu* gpu,
398 const GrTextureDesc& desc,
399 uint32_t v[4]) {
400 // Instead of a client-provided key of the texture contents
401 // we create a key of from the descriptor.
402 GrContext::TextureKey descKey = desc.fAALevel |
403 (desc.fFlags << 8) |
404 ((uint64_t) desc.fFormat << 32);
405 // this code path isn't friendly to tiling with NPOT restricitons
406 // We just pass ClampNoFilter()
407 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
408 desc.fWidth, desc.fHeight, true, v);
409}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000410}
411
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412GrContext::TextureCacheEntry GrContext::lockScratchTexture(
413 const GrTextureDesc& inDesc,
414 ScratchTexMatch match) {
415
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000416 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000417 if (kExact_ScratchTexMatch != match) {
418 // bin by pow2 with a reasonable min
419 static const int MIN_SIZE = 256;
420 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
421 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
422 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000423
424 uint32_t p0 = desc.fFormat;
425 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
426
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000428 int origWidth = desc.fWidth;
429 int origHeight = desc.fHeight;
430 bool doubledW = false;
431 bool doubledH = false;
432
433 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 uint32_t v[4];
435 gen_scratch_tex_key_values(fGpu, desc, v);
436 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000437 entry = fTextureCache->findAndLock(key,
438 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000439 // if we miss, relax the fit of the flags...
440 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000442 break;
443 }
444 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
445 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
446 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
447 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
448 } else if (!doubledW) {
449 desc.fFlags = inDesc.fFlags;
450 desc.fWidth *= 2;
451 doubledW = true;
452 } else if (!doubledH) {
453 desc.fFlags = inDesc.fFlags;
454 desc.fWidth = origWidth;
455 desc.fHeight *= 2;
456 doubledH = true;
457 } else {
458 break;
459 }
460
461 } while (true);
462
463 if (NULL == entry) {
464 desc.fFlags = inDesc.fFlags;
465 desc.fWidth = origWidth;
466 desc.fHeight = origHeight;
467 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
468 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000469 uint32_t v[4];
470 gen_scratch_tex_key_values(fGpu, desc, v);
471 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000472 entry = fTextureCache->createAndLock(key, texture);
473 }
474 }
475
476 // If the caller gives us the same desc/sampler twice we don't want
477 // to return the same texture the second time (unless it was previously
478 // released). So we detach the entry from the cache and reattach at release.
479 if (NULL != entry) {
480 fTextureCache->detach(entry);
481 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000482 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000483}
484
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485void GrContext::unlockTexture(TextureCacheEntry entry) {
486 // If this is a scratch texture we detached it from the cache
487 // while it was locked (to avoid two callers simultaneously getting
488 // the same texture).
489 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
490 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000491 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000492 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000493 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000494}
495
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000496GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000497 void* srcData,
498 size_t rowBytes) {
499 return fGpu->createTexture(desc, srcData, rowBytes);
500}
501
502void GrContext::getTextureCacheLimits(int* maxTextures,
503 size_t* maxTextureBytes) const {
504 fTextureCache->getLimits(maxTextures, maxTextureBytes);
505}
506
507void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
508 fTextureCache->setLimits(maxTextures, maxTextureBytes);
509}
510
bsalomon@google.com91958362011-06-13 17:58:13 +0000511int GrContext::getMaxTextureSize() const {
512 return fGpu->maxTextureSize();
513}
514
515int GrContext::getMaxRenderTargetSize() const {
516 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000517}
518
519///////////////////////////////////////////////////////////////////////////////
520
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000521GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
522 // validate flags here so that GrGpu subclasses don't have to check
523 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
524 0 != desc.fRenderTargetFlags) {
525 return NULL;
526 }
bsalomon@google.com47370822011-08-02 15:29:38 +0000527#if !GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000528 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
529 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
530 return NULL;
531 }
532 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
533 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
534 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
535 return NULL;
536 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000537#else
538 if (desc.fSampleCnt &&
539 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
540 return NULL;
541 }
542 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
543 desc.fSampleCnt &&
544 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
545 return NULL;
546 }
547#endif
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000548 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000549}
550
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000551///////////////////////////////////////////////////////////////////////////////
552
bsalomon@google.com27847de2011-02-22 20:59:41 +0000553bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000554 int width, int height) const {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000555 if (!fGpu->supports8BitPalette()) {
556 return false;
557 }
558
559
560 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
561
562 if (!isPow2) {
563 if (!fGpu->npotTextureSupport()) {
564 return false;
565 }
566
567 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
568 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
569 if (tiled && !fGpu->npotTextureTileSupport()) {
570 return false;
571 }
572 }
573 return true;
574}
575
576////////////////////////////////////////////////////////////////////////////////
577
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000578const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
579
bsalomon@google.com27847de2011-02-22 20:59:41 +0000580void GrContext::setClip(const GrClip& clip) {
581 fGpu->setClip(clip);
582 fGpu->enableState(GrDrawTarget::kClip_StateBit);
583}
584
585void GrContext::setClip(const GrIRect& rect) {
586 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000587 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588 fGpu->setClip(clip);
589}
590
591////////////////////////////////////////////////////////////////////////////////
592
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000593void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000594 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000595 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596}
597
598void GrContext::drawPaint(const GrPaint& paint) {
599 // set rect to be big enough to fill the space, but not super-huge, so we
600 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000601 GrRect r;
602 r.setLTRB(0, 0,
603 GrIntToScalar(getRenderTarget()->width()),
604 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000605 GrMatrix inverse;
606 if (fGpu->getViewInverse(&inverse)) {
607 inverse.mapRect(&r);
608 } else {
609 GrPrintf("---- fGpu->getViewInverse failed\n");
610 }
611 this->drawRect(paint, r);
612}
613
bsalomon@google.com205d4602011-04-25 12:43:45 +0000614////////////////////////////////////////////////////////////////////////////////
615
bsalomon@google.com91958362011-06-13 17:58:13 +0000616struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000617 enum Downsample {
618 k4x4TwoPass_Downsample,
619 k4x4SinglePass_Downsample,
620 kFSAA_Downsample
621 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000622 int fTileSizeX;
623 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000624 int fTileCountX;
625 int fTileCountY;
626 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000627 GrAutoScratchTexture fOffscreen0;
628 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000629 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000630 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000631};
632
bsalomon@google.com471d4712011-08-23 15:45:25 +0000633bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000634 const GrPaint& paint,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000635 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000636#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000637 return false;
638#else
639 if (!paint.fAntiAlias) {
640 return false;
641 }
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000642 // Line primitves are always rasterized as 1 pixel wide.
643 // Super-sampling would make them too thin but MSAA would be OK.
644 if (isHairLines &&
645 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA())) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000646 return false;
647 }
648 if (target->getRenderTarget()->isMultisampled()) {
649 return false;
650 }
651 // we have to be sure that the blend equation is expressible
652 // as simple src / dst coeffecients when the source
653 // is already modulated by the coverage fraction.
654 // We could use dual-source blending to get the correct per-pixel
655 // dst coeffecient for the remaining cases.
656 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
657 kOne_BlendCoeff != paint.fDstBlendCoeff &&
658 kISA_BlendCoeff != paint.fDstBlendCoeff) {
659 return false;
660 }
661 return true;
662#endif
663}
664
bsalomon@google.com91958362011-06-13 17:58:13 +0000665bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000666 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000667 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000668 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000669 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000670
671 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000672
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000673 GrAssert(NULL == record->fOffscreen0.texture());
674 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000675 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000676
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000677 int boundW = boundRect.width();
678 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000679
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000680 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000681
682 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
683 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
684
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000685 if (requireStencil) {
686 desc.fFlags = kRenderTarget_GrTextureFlagBit;
687 } else {
688 desc.fFlags = kRenderTarget_GrTextureFlagBit |
689 kNoStencil_GrTextureFlagBit;
690 }
691
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000692 desc.fFormat = kRGBA_8888_GrPixelConfig;
693
bsalomon@google.com91958362011-06-13 17:58:13 +0000694 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000695 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000696 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000697 desc.fAALevel = kMed_GrAALevel;
698 } else {
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000699 record->fDownsample = (fGpu->supportsShaders()) ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000700 OffscreenRecord::k4x4SinglePass_Downsample :
701 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000702 record->fScale = OFFSCREEN_SSAA_SCALE;
703 // both downsample paths assume this
704 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000705 desc.fAALevel = kNone_GrAALevel;
706 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000707 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
708 // of simple circles?
709 if (pr) {
710 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
711 }
712
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000713 desc.fWidth *= record->fScale;
714 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000715 record->fOffscreen0.set(this, desc);
716 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000717 return false;
718 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000719 // the approximate lookup might have given us some slop space, might as well
720 // use it when computing the tiles size.
721 // these are scale values, will adjust after considering
722 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000723 record->fTileSizeX = record->fOffscreen0.texture()->width();
724 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000725
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000726 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000727 desc.fWidth /= 2;
728 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000729 record->fOffscreen1.set(this, desc);
730 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000731 return false;
732 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000733 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000734 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000735 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000736 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000737 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000738 record->fTileSizeX /= record->fScale;
739 record->fTileSizeY /= record->fScale;
740
741 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
742 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
743
tomhudson@google.com237a4612011-07-19 15:44:00 +0000744 record->fClip = target->getClip();
745
bsalomon@google.com91958362011-06-13 17:58:13 +0000746 target->saveCurrentDrawState(&record->fSavedState);
747 return true;
748}
749
750void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
751 const GrIRect& boundRect,
752 int tileX, int tileY,
753 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000754
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000755 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000756 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000757
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000758 GrPaint tempPaint;
759 tempPaint.reset();
760 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000761 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000762
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000763 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000764 int left = boundRect.fLeft + tileX * record->fTileSizeX;
765 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000766 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000767 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000768 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000769 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000770 target->postConcatViewMatrix(scaleM);
771
bsalomon@google.com91958362011-06-13 17:58:13 +0000772 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000773 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000774 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000775 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000776 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
777 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000778 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000779#if 0
780 // visualize tile boundaries by setting edges of offscreen to white
781 // and interior to tranparent. black.
782 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000783
bsalomon@google.com91958362011-06-13 17:58:13 +0000784 static const int gOffset = 2;
785 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
786 record->fScale * w - gOffset,
787 record->fScale * h - gOffset);
788 target->clear(&clear2, 0x0);
789#else
790 target->clear(&clear, 0x0);
791#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000792}
793
bsalomon@google.com91958362011-06-13 17:58:13 +0000794void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795 const GrPaint& paint,
796 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000797 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000798 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000799 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000800 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000801 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000802 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000803 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
804 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000805 tileRect.fRight = (tileX == record->fTileCountX-1) ?
806 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000807 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000808 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
809 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000811
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000812 GrSamplerState::Filter filter;
813 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
814 filter = GrSamplerState::k4x4Downsample_Filter;
815 } else {
816 filter = GrSamplerState::kBilinear_Filter;
817 }
818
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000819 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000820 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000821 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000822
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000823 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000824 int scale;
825
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000826 enum {
827 kOffscreenStage = GrPaint::kTotalStages,
828 };
829
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000830 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000831 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000832 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000833 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000834
835 // Do 2x2 downsample from first to second
836 target->setTexture(kOffscreenStage, src);
837 target->setRenderTarget(dst);
838 target->setViewMatrix(GrMatrix::I());
839 sampleM.setScale(scale * GR_Scalar1 / src->width(),
840 scale * GR_Scalar1 / src->height());
841 sampler.setMatrix(sampleM);
842 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000843 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
844 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000845 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
846
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000847 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000848 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000849 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000850 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000852 } else {
853 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
854 record->fDownsample);
855 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000856 }
857
bsalomon@google.com91958362011-06-13 17:58:13 +0000858 // setup for draw back to main RT, we use the original
859 // draw state setup by the caller plus an additional coverage
860 // stage to handle the AA resolve. Also, we use an identity
861 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000862 int stageMask = paint.getActiveStageMask();
863
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000865 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000866
867 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000868 GrMatrix invVM;
869 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000870 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871 }
872 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000873 // This is important when tiling, otherwise second tile's
874 // pass 1 view matrix will be incorrect.
875 GrDrawTarget::AutoViewMatrixRestore avmr(target);
876
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000877 target->setViewMatrix(GrMatrix::I());
878
879 target->setTexture(kOffscreenStage, src);
880 sampleM.setScale(scale * GR_Scalar1 / src->width(),
881 scale * GR_Scalar1 / src->height());
882 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000883 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000884 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000885 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000886
reed@google.com20efde72011-05-09 17:00:02 +0000887 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000888 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000889 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000890 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000891}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000892
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000893void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
894 GrPathRenderer* pr,
895 OffscreenRecord* record) {
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000896 if (pr) {
897 // Counterpart of scale() in prepareForOffscreenAA()
898 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
899 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000900 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000901}
902
903////////////////////////////////////////////////////////////////////////////////
904
bsalomon@google.com27847de2011-02-22 20:59:41 +0000905/* create a triangle strip that strokes the specified triangle. There are 8
906 unique vertices, but we repreat the last 2 to close up. Alternatively we
907 could use an indices array, and then only send 8 verts, but not sure that
908 would be faster.
909 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000910static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000911 GrScalar width) {
912 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000913 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000914
915 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
916 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
917 verts[2].set(rect.fRight - rad, rect.fTop + rad);
918 verts[3].set(rect.fRight + rad, rect.fTop - rad);
919 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
920 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
921 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
922 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
923 verts[8] = verts[0];
924 verts[9] = verts[1];
925}
926
bsalomon@google.com205d4602011-04-25 12:43:45 +0000927static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000928 // FIXME: This was copied from SkGpuDevice, seems like
929 // we should have already smeared a in caller if that
930 // is what is desired.
931 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000932 unsigned a = GrColorUnpackA(paint.fColor);
933 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000934 } else {
935 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000936 }
937}
938
939static void setInsetFan(GrPoint* pts, size_t stride,
940 const GrRect& r, GrScalar dx, GrScalar dy) {
941 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
942}
943
944static const uint16_t gFillAARectIdx[] = {
945 0, 1, 5, 5, 4, 0,
946 1, 2, 6, 6, 5, 1,
947 2, 3, 7, 7, 6, 2,
948 3, 0, 4, 4, 7, 3,
949 4, 5, 6, 6, 7, 4,
950};
951
952int GrContext::aaFillRectIndexCount() const {
953 return GR_ARRAY_COUNT(gFillAARectIdx);
954}
955
956GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
957 if (NULL == fAAFillRectIndexBuffer) {
958 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
959 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000960 if (NULL != fAAFillRectIndexBuffer) {
961 #if GR_DEBUG
962 bool updated =
963 #endif
964 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
965 sizeof(gFillAARectIdx));
966 GR_DEBUGASSERT(updated);
967 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000968 }
969 return fAAFillRectIndexBuffer;
970}
971
972static const uint16_t gStrokeAARectIdx[] = {
973 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
974 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
975 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
976 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
977
978 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
979 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
980 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
981 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
982
983 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
984 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
985 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
986 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
987};
988
989int GrContext::aaStrokeRectIndexCount() const {
990 return GR_ARRAY_COUNT(gStrokeAARectIdx);
991}
992
993GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
994 if (NULL == fAAStrokeRectIndexBuffer) {
995 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
996 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000997 if (NULL != fAAStrokeRectIndexBuffer) {
998 #if GR_DEBUG
999 bool updated =
1000 #endif
1001 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1002 sizeof(gStrokeAARectIdx));
1003 GR_DEBUGASSERT(updated);
1004 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001005 }
1006 return fAAStrokeRectIndexBuffer;
1007}
1008
1009void GrContext::fillAARect(GrDrawTarget* target,
1010 const GrPaint& paint,
1011 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001012 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1013 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001014
1015 size_t vsize = GrDrawTarget::VertexSize(layout);
1016
1017 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001018 if (!geo.succeeded()) {
1019 GrPrintf("Failed to get space for vertices!\n");
1020 return;
1021 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001022 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1023 if (NULL == indexBuffer) {
1024 GrPrintf("Failed to create index buffer!\n");
1025 return;
1026 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001027
1028 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1029
1030 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1031 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1032
1033 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1034 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1035
1036 verts += sizeof(GrPoint);
1037 for (int i = 0; i < 4; ++i) {
1038 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1039 }
1040
1041 GrColor innerColor = getColorForMesh(paint);
1042 verts += 4 * vsize;
1043 for (int i = 0; i < 4; ++i) {
1044 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1045 }
1046
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001047 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001048
1049 target->drawIndexed(kTriangles_PrimitiveType, 0,
1050 0, 8, this->aaFillRectIndexCount());
1051}
1052
1053void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1054 const GrRect& devRect, const GrVec& devStrokeSize) {
1055 const GrScalar& dx = devStrokeSize.fX;
1056 const GrScalar& dy = devStrokeSize.fY;
1057 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1058 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1059
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001060 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1061 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001062
1063 GrScalar spare;
1064 {
1065 GrScalar w = devRect.width() - dx;
1066 GrScalar h = devRect.height() - dy;
1067 spare = GrMin(w, h);
1068 }
1069
1070 if (spare <= 0) {
1071 GrRect r(devRect);
1072 r.inset(-rx, -ry);
1073 fillAARect(target, paint, r);
1074 return;
1075 }
1076
1077 size_t vsize = GrDrawTarget::VertexSize(layout);
1078
1079 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001080 if (!geo.succeeded()) {
1081 GrPrintf("Failed to get space for vertices!\n");
1082 return;
1083 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001084 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1085 if (NULL == indexBuffer) {
1086 GrPrintf("Failed to create index buffer!\n");
1087 return;
1088 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001089
1090 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1091
1092 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1093 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1094 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1095 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1096
1097 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1098 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1099 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1100 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1101
1102 verts += sizeof(GrPoint);
1103 for (int i = 0; i < 4; ++i) {
1104 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1105 }
1106
1107 GrColor innerColor = getColorForMesh(paint);
1108 verts += 4 * vsize;
1109 for (int i = 0; i < 8; ++i) {
1110 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1111 }
1112
1113 verts += 8 * vsize;
1114 for (int i = 0; i < 8; ++i) {
1115 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1116 }
1117
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001118 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001119 target->drawIndexed(kTriangles_PrimitiveType,
1120 0, 0, 16, aaStrokeRectIndexCount());
1121}
1122
reed@google.com20efde72011-05-09 17:00:02 +00001123/**
1124 * Returns true if the rects edges are integer-aligned.
1125 */
1126static bool isIRect(const GrRect& r) {
1127 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1128 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1129}
1130
bsalomon@google.com205d4602011-04-25 12:43:45 +00001131static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001132 const GrPaint& paint,
1133 const GrRect& rect,
1134 GrScalar width,
1135 const GrMatrix* matrix,
1136 GrMatrix* combinedMatrix,
1137 GrRect* devRect) {
1138 // we use a simple alpha ramp to do aa on axis-aligned rects
1139 // do AA with alpha ramp if the caller requested AA, the rect
1140 // will be axis-aligned,the render target is not
1141 // multisampled, and the rect won't land on integer coords.
1142
1143 if (!paint.fAntiAlias) {
1144 return false;
1145 }
1146
1147 if (target->getRenderTarget()->isMultisampled()) {
1148 return false;
1149 }
1150
bsalomon@google.com471d4712011-08-23 15:45:25 +00001151 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001152 return false;
1153 }
1154
1155 if (!target->getViewMatrix().preservesAxisAlignment()) {
1156 return false;
1157 }
1158
1159 if (NULL != matrix &&
1160 !matrix->preservesAxisAlignment()) {
1161 return false;
1162 }
1163
1164 *combinedMatrix = target->getViewMatrix();
1165 if (NULL != matrix) {
1166 combinedMatrix->preConcat(*matrix);
1167 GrAssert(combinedMatrix->preservesAxisAlignment());
1168 }
1169
1170 combinedMatrix->mapRect(devRect, rect);
1171 devRect->sort();
1172
1173 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001174 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001175 } else {
1176 return true;
1177 }
1178}
1179
bsalomon@google.com27847de2011-02-22 20:59:41 +00001180void GrContext::drawRect(const GrPaint& paint,
1181 const GrRect& rect,
1182 GrScalar width,
1183 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001184 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001185
1186 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001187 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001188
bsalomon@google.com205d4602011-04-25 12:43:45 +00001189 GrRect devRect = rect;
1190 GrMatrix combinedMatrix;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001191 bool doAA = apply_aa_to_rect(target, paint, rect, width, matrix,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001192 &combinedMatrix, &devRect);
1193
1194 if (doAA) {
1195 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001196 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001197 GrMatrix inv;
1198 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001199 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001200 }
1201 }
1202 target->setViewMatrix(GrMatrix::I());
1203 if (width >= 0) {
1204 GrVec strokeSize;;
1205 if (width > 0) {
1206 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001207 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001208 strokeSize.setAbs(strokeSize);
1209 } else {
1210 strokeSize.set(GR_Scalar1, GR_Scalar1);
1211 }
1212 strokeAARect(target, paint, devRect, strokeSize);
1213 } else {
1214 fillAARect(target, paint, devRect);
1215 }
1216 return;
1217 }
1218
bsalomon@google.com27847de2011-02-22 20:59:41 +00001219 if (width >= 0) {
1220 // TODO: consider making static vertex buffers for these cases.
1221 // Hairline could be done by just adding closing vertex to
1222 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001223 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1224
bsalomon@google.com27847de2011-02-22 20:59:41 +00001225 static const int worstCaseVertCount = 10;
1226 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1227
1228 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001229 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001230 return;
1231 }
1232
1233 GrPrimitiveType primType;
1234 int vertCount;
1235 GrPoint* vertex = geo.positions();
1236
1237 if (width > 0) {
1238 vertCount = 10;
1239 primType = kTriangleStrip_PrimitiveType;
1240 setStrokeRectStrip(vertex, rect, width);
1241 } else {
1242 // hairline
1243 vertCount = 5;
1244 primType = kLineStrip_PrimitiveType;
1245 vertex[0].set(rect.fLeft, rect.fTop);
1246 vertex[1].set(rect.fRight, rect.fTop);
1247 vertex[2].set(rect.fRight, rect.fBottom);
1248 vertex[3].set(rect.fLeft, rect.fBottom);
1249 vertex[4].set(rect.fLeft, rect.fTop);
1250 }
1251
1252 GrDrawTarget::AutoViewMatrixRestore avmr;
1253 if (NULL != matrix) {
1254 avmr.set(target);
1255 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001256 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001257 }
1258
1259 target->drawNonIndexed(primType, 0, vertCount);
1260 } else {
1261 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001262 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001263 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1264 if (NULL == sqVB) {
1265 GrPrintf("Failed to create static rect vb.\n");
1266 return;
1267 }
1268 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001269 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1270 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001271 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001272 0, rect.height(), rect.fTop,
1273 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001274
1275 if (NULL != matrix) {
1276 m.postConcat(*matrix);
1277 }
1278
1279 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001280 target->preConcatSamplerMatrices(stageMask, m);
1281
bsalomon@google.com27847de2011-02-22 20:59:41 +00001282 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1283 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001284 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001285 #endif
1286 }
1287}
1288
1289void GrContext::drawRectToRect(const GrPaint& paint,
1290 const GrRect& dstRect,
1291 const GrRect& srcRect,
1292 const GrMatrix* dstMatrix,
1293 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001294 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001295
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001296 // srcRect refers to paint's first texture
1297 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298 drawRect(paint, dstRect, -1, dstMatrix);
1299 return;
1300 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001301
bsalomon@google.com27847de2011-02-22 20:59:41 +00001302 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1303
1304#if GR_STATIC_RECT_VB
1305 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001306
1307 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001308 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1309
1310 GrMatrix m;
1311
1312 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1313 0, dstRect.height(), dstRect.fTop,
1314 0, 0, GrMatrix::I()[8]);
1315 if (NULL != dstMatrix) {
1316 m.postConcat(*dstMatrix);
1317 }
1318 target->preConcatViewMatrix(m);
1319
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001320 // srcRect refers to first stage
1321 int otherStageMask = paint.getActiveStageMask() &
1322 (~(1 << GrPaint::kFirstTextureStage));
1323 if (otherStageMask) {
1324 target->preConcatSamplerMatrices(otherStageMask, m);
1325 }
1326
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1328 0, srcRect.height(), srcRect.fTop,
1329 0, 0, GrMatrix::I()[8]);
1330 if (NULL != srcMatrix) {
1331 m.postConcat(*srcMatrix);
1332 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001333 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001334
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001335 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1336 if (NULL == sqVB) {
1337 GrPrintf("Failed to create static rect vb.\n");
1338 return;
1339 }
1340 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001341 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1342#else
1343
1344 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001345#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001346 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001347#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001348 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1349#endif
1350
1351 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1352 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1353 srcRects[0] = &srcRect;
1354 srcMatrices[0] = srcMatrix;
1355
1356 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1357#endif
1358}
1359
1360void GrContext::drawVertices(const GrPaint& paint,
1361 GrPrimitiveType primitiveType,
1362 int vertexCount,
1363 const GrPoint positions[],
1364 const GrPoint texCoords[],
1365 const GrColor colors[],
1366 const uint16_t indices[],
1367 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001368 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001369
1370 GrDrawTarget::AutoReleaseGeometry geo;
1371
1372 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1373
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001374 bool hasTexCoords[GrPaint::kTotalStages] = {
1375 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1376 0 // remaining stages use positions
1377 };
1378
1379 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001380
1381 if (NULL != colors) {
1382 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001383 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001384 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001385
1386 if (sizeof(GrPoint) != vertexSize) {
1387 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001388 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001389 return;
1390 }
1391 int texOffsets[GrDrawTarget::kMaxTexCoords];
1392 int colorOffset;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001393 int edgeOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001394 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1395 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001396 &colorOffset,
1397 &edgeOffset);
1398 GrAssert(-1 == edgeOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001399 void* curVertex = geo.vertices();
1400
1401 for (int i = 0; i < vertexCount; ++i) {
1402 *((GrPoint*)curVertex) = positions[i];
1403
1404 if (texOffsets[0] > 0) {
1405 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1406 }
1407 if (colorOffset > 0) {
1408 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1409 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001410 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411 }
1412 } else {
1413 target->setVertexSourceToArray(layout, positions, vertexCount);
1414 }
1415
bsalomon@google.com91958362011-06-13 17:58:13 +00001416 // we don't currently apply offscreen AA to this path. Need improved
1417 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001418
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001419 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001420 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001421 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001422 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001423 target->drawNonIndexed(primitiveType, 0, vertexCount);
1424 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001425}
1426
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001427///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001428
reed@google.com07f3ee12011-05-16 17:21:57 +00001429void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1430 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001431
bsalomon@google.com27847de2011-02-22 20:59:41 +00001432 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001433 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1434 if (NULL == pr) {
1435 GrPrintf("Unable to find path renderer compatible with path.\n");
1436 return;
1437 }
1438
bsalomon@google.comee435122011-07-01 14:57:55 +00001439 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1440 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001442 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001443 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001444
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001445 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001446
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001447 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001448 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1449 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001450 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001451 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001452 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001453 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001454 return;
1455 }
1456 }
reed@google.com70c136e2011-06-03 19:51:26 +00001457
reed@google.com07f3ee12011-05-16 17:21:57 +00001458 GrRect pathBounds = path.getBounds();
1459 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001460 if (NULL != translate) {
1461 pathBounds.offset(*translate);
1462 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001463 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001464 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001465 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001466 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001467 return;
1468 }
1469 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001470 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001471 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1472 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001473 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1474 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1475 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001476 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001477 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1478 }
1479 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001480 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001481 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001482 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1483 GrRect rect;
1484 if (clipIBounds.fTop < bound.fTop) {
1485 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1486 clipIBounds.fRight, bound.fTop);
1487 target->drawSimpleRect(rect, NULL, stageMask);
1488 }
1489 if (clipIBounds.fLeft < bound.fLeft) {
1490 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1491 bound.fLeft, bound.fBottom);
1492 target->drawSimpleRect(rect, NULL, stageMask);
1493 }
1494 if (clipIBounds.fRight > bound.fRight) {
1495 rect.setLTRB(bound.fRight, bound.fTop,
1496 clipIBounds.fRight, bound.fBottom);
1497 target->drawSimpleRect(rect, NULL, stageMask);
1498 }
1499 if (clipIBounds.fBottom > bound.fBottom) {
1500 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1501 clipIBounds.fRight, clipIBounds.fBottom);
1502 target->drawSimpleRect(rect, NULL, stageMask);
1503 }
1504 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001505 return;
1506 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001507 }
1508 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001509}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001510
bsalomon@google.com27847de2011-02-22 20:59:41 +00001511////////////////////////////////////////////////////////////////////////////////
1512
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001513bool GrContext::supportsShaders() const {
1514 return fGpu->supportsShaders();
1515}
1516
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001517void GrContext::flush(int flagsBitfield) {
1518 if (kDiscard_FlushBit & flagsBitfield) {
1519 fDrawBuffer->reset();
1520 } else {
1521 flushDrawBuffer();
1522 }
1523
1524 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001525 fGpu->forceRenderTargetFlush();
1526 }
1527}
1528
1529void GrContext::flushText() {
1530 if (kText_DrawCategory == fLastDrawCategory) {
1531 flushDrawBuffer();
1532 }
1533}
1534
1535void GrContext::flushDrawBuffer() {
1536#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001537 if (fDrawBuffer) {
1538 fDrawBuffer->playback(fGpu);
1539 fDrawBuffer->reset();
1540 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001541#endif
1542}
1543
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001544bool GrContext::readTexturePixels(GrTexture* texture,
1545 int left, int top, int width, int height,
1546 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001547 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001548
1549 // TODO: code read pixels for textures that aren't rendertargets
1550
1551 this->flush();
1552 GrRenderTarget* target = texture->asRenderTarget();
1553 if (NULL != target) {
1554 return fGpu->readPixels(target,
1555 left, top, width, height,
1556 config, buffer);
1557 } else {
1558 return false;
1559 }
1560}
1561
1562bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1563 int left, int top, int width, int height,
1564 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001565 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001566 uint32_t flushFlags = 0;
1567 if (NULL == target) {
1568 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1569 }
1570
1571 this->flush(flushFlags);
1572 return fGpu->readPixels(target,
1573 left, top, width, height,
1574 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001575}
1576
1577void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001578 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001579 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001580 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001581
1582 // TODO: when underlying api has a direct way to do this we should use it
1583 // (e.g. glDrawPixels on desktop GL).
1584
bsalomon@google.com5c638652011-07-18 19:31:59 +00001585 this->flush(true);
1586
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001587 const GrTextureDesc desc = {
1588 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001589 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001590 GrAutoScratchTexture ast(this, desc);
1591 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001592 if (NULL == texture) {
1593 return;
1594 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001595 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001596
bsalomon@google.com27847de2011-02-22 20:59:41 +00001597 GrDrawTarget::AutoStateRestore asr(fGpu);
1598
1599 GrMatrix matrix;
1600 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1601 fGpu->setViewMatrix(matrix);
1602
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001603 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001604 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1605 fGpu->setAlpha(0xFF);
1606 fGpu->setBlendFunc(kOne_BlendCoeff,
1607 kZero_BlendCoeff);
1608 fGpu->setTexture(0, texture);
1609
1610 GrSamplerState sampler;
1611 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001612 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001613 sampler.setMatrix(matrix);
1614 fGpu->setSamplerState(0, sampler);
1615
1616 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1617 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001618 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001619 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1620 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001621 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001622 return;
1623 }
1624 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1625 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1626}
1627////////////////////////////////////////////////////////////////////////////////
1628
1629void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001630
1631 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1632 int s = i + GrPaint::kFirstTextureStage;
1633 target->setTexture(s, paint.getTexture(i));
1634 target->setSamplerState(s, *paint.getTextureSampler(i));
1635 }
1636
1637 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1638
1639 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1640 int s = i + GrPaint::kFirstMaskStage;
1641 target->setTexture(s, paint.getMask(i));
1642 target->setSamplerState(s, *paint.getMaskSampler(i));
1643 }
1644
bsalomon@google.com27847de2011-02-22 20:59:41 +00001645 target->setColor(paint.fColor);
1646
1647 if (paint.fDither) {
1648 target->enableState(GrDrawTarget::kDither_StateBit);
1649 } else {
1650 target->disableState(GrDrawTarget::kDither_StateBit);
1651 }
1652 if (paint.fAntiAlias) {
1653 target->enableState(GrDrawTarget::kAntialias_StateBit);
1654 } else {
1655 target->disableState(GrDrawTarget::kAntialias_StateBit);
1656 }
1657 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001658 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001659}
1660
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001661GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001662 DrawCategory category) {
1663 if (category != fLastDrawCategory) {
1664 flushDrawBuffer();
1665 fLastDrawCategory = category;
1666 }
1667 SetPaint(paint, fGpu);
1668 GrDrawTarget* target = fGpu;
1669 switch (category) {
1670 case kText_DrawCategory:
1671#if DEFER_TEXT_RENDERING
1672 target = fDrawBuffer;
1673 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1674#else
1675 target = fGpu;
1676#endif
1677 break;
1678 case kUnbuffered_DrawCategory:
1679 target = fGpu;
1680 break;
1681 case kBuffered_DrawCategory:
1682 target = fDrawBuffer;
1683 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1684 break;
1685 }
1686 return target;
1687}
1688
bsalomon@google.com30085192011-08-19 15:42:31 +00001689GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1690 const GrPath& path,
1691 GrPathFill fill) {
1692 if (NULL == fPathRendererChain) {
1693 fPathRendererChain =
1694 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1695 }
1696 return fPathRendererChain->getPathRenderer(target, path, fill);
1697}
1698
bsalomon@google.com27847de2011-02-22 20:59:41 +00001699////////////////////////////////////////////////////////////////////////////////
1700
bsalomon@google.com27847de2011-02-22 20:59:41 +00001701void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001702 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001703 fGpu->setRenderTarget(target);
1704}
1705
1706GrRenderTarget* GrContext::getRenderTarget() {
1707 return fGpu->getRenderTarget();
1708}
1709
1710const GrRenderTarget* GrContext::getRenderTarget() const {
1711 return fGpu->getRenderTarget();
1712}
1713
1714const GrMatrix& GrContext::getMatrix() const {
1715 return fGpu->getViewMatrix();
1716}
1717
1718void GrContext::setMatrix(const GrMatrix& m) {
1719 fGpu->setViewMatrix(m);
1720}
1721
1722void GrContext::concatMatrix(const GrMatrix& m) const {
1723 fGpu->preConcatViewMatrix(m);
1724}
1725
1726static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1727 intptr_t mask = 1 << shift;
1728 if (pred) {
1729 bits |= mask;
1730 } else {
1731 bits &= ~mask;
1732 }
1733 return bits;
1734}
1735
1736void GrContext::resetStats() {
1737 fGpu->resetStats();
1738}
1739
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001740const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001741 return fGpu->getStats();
1742}
1743
1744void GrContext::printStats() const {
1745 fGpu->printStats();
1746}
1747
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001748GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001749 fGpu = gpu;
1750 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001751 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001752
bsalomon@google.com30085192011-08-19 15:42:31 +00001753 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001754
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001755 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1756 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001757 fFontCache = new GrFontCache(fGpu);
1758
1759 fLastDrawCategory = kUnbuffered_DrawCategory;
1760
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001761 fDrawBuffer = NULL;
1762 fDrawBufferVBAllocPool = NULL;
1763 fDrawBufferIBAllocPool = NULL;
1764
bsalomon@google.com205d4602011-04-25 12:43:45 +00001765 fAAFillRectIndexBuffer = NULL;
1766 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001767
1768 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1769 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1770 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1771 }
1772 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001773
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001774 this->setupDrawBuffer();
1775}
1776
1777void GrContext::setupDrawBuffer() {
1778
1779 GrAssert(NULL == fDrawBuffer);
1780 GrAssert(NULL == fDrawBufferVBAllocPool);
1781 GrAssert(NULL == fDrawBufferIBAllocPool);
1782
bsalomon@google.com27847de2011-02-22 20:59:41 +00001783#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001784 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001785 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001786 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1787 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001788 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001789 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001790 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001791 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1792
bsalomon@google.com471d4712011-08-23 15:45:25 +00001793 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1794 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001795 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001796#endif
1797
1798#if BATCH_RECT_TO_RECT
1799 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1800#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001801}
1802
bsalomon@google.com27847de2011-02-22 20:59:41 +00001803GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1804 GrDrawTarget* target;
1805#if DEFER_TEXT_RENDERING
1806 target = prepareToDraw(paint, kText_DrawCategory);
1807#else
1808 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1809#endif
1810 SetPaint(paint, target);
1811 return target;
1812}
1813
1814const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1815 return fGpu->getQuadIndexBuffer();
1816}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001817
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001818void GrContext::convolveInX(GrTexture* texture,
1819 const SkRect& rect,
1820 const float* kernel,
1821 int kernelWidth) {
1822 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1823 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1824}
1825
1826void GrContext::convolveInY(GrTexture* texture,
1827 const SkRect& rect,
1828 const float* kernel,
1829 int kernelWidth) {
1830 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1831 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1832}
1833
1834void GrContext::convolve(GrTexture* texture,
1835 const SkRect& rect,
1836 float imageIncrement[2],
1837 const float* kernel,
1838 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001839 GrDrawTarget::AutoStateRestore asr(fGpu);
1840 GrMatrix sampleM;
1841 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1842 GrSamplerState::kClamp_WrapMode,
1843 GrSamplerState::kConvolution_Filter);
1844 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001845 sampleM.setScale(GR_Scalar1 / texture->width(),
1846 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001847 sampler.setMatrix(sampleM);
1848 fGpu->setSamplerState(0, sampler);
1849 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001850 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001851 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001852 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1853}