blob: 8eb8c63e7e1c716bbc55530d17115cce9f3e01bc [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000021#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000022
bsalomon@google.com91958362011-06-13 17:58:13 +000023// Using MSAA seems to be slower for some yet unknown reason.
24#define PREFER_MSAA_OFFSCREEN_AA 0
25#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000026
bsalomon@google.com27847de2011-02-22 20:59:41 +000027#define DEFER_TEXT_RENDERING 1
28
29#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
30
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000031static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
32static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000033
34static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
35static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
36
37// We are currently only batching Text and drawRectToRect, both
38// of which use the quad index buffer.
39static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
40static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
41
bsalomon@google.com05ef5102011-05-02 21:14:59 +000042GrContext* GrContext::Create(GrEngine engine,
43 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000044 GrContext* ctx = NULL;
45 GrGpu* fGpu = GrGpu::Create(engine, context3D);
46 if (NULL != fGpu) {
47 ctx = new GrContext(fGpu);
48 fGpu->unref();
49 }
50 return ctx;
51}
52
53GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000054 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000055}
56
57GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000058 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000059 delete fTextureCache;
60 delete fFontCache;
61 delete fDrawBuffer;
62 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000063 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000064
bsalomon@google.com205d4602011-04-25 12:43:45 +000065 GrSafeUnref(fAAFillRectIndexBuffer);
66 GrSafeUnref(fAAStrokeRectIndexBuffer);
67 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000068 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000069}
70
bsalomon@google.com8fe72472011-03-30 21:26:44 +000071void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000072 contextDestroyed();
73 this->setupDrawBuffer();
74}
75
76void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000077 // abandon first to so destructors
78 // don't try to free the resources in the API.
79 fGpu->abandonResources();
80
bsalomon@google.com30085192011-08-19 15:42:31 +000081 // a path renderer may be holding onto resources that
82 // are now unusable
83 GrSafeSetNull(fPathRendererChain);
84
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBuffer;
86 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000087
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBufferVBAllocPool;
89 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferIBAllocPool;
92 fDrawBufferIBAllocPool = NULL;
93
bsalomon@google.com205d4602011-04-25 12:43:45 +000094 GrSafeSetNull(fAAFillRectIndexBuffer);
95 GrSafeSetNull(fAAStrokeRectIndexBuffer);
96
bsalomon@google.com8fe72472011-03-30 21:26:44 +000097 fTextureCache->removeAll();
98 fFontCache->freeAll();
99 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100}
101
102void GrContext::resetContext() {
103 fGpu->markContextDirty();
104}
105
106void GrContext::freeGpuResources() {
107 this->flush();
108 fTextureCache->removeAll();
109 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000110 // a path renderer may be holding onto resources
111 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000112}
113
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000114////////////////////////////////////////////////////////////////////////////////
115
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000116int GrContext::PaintStageVertexLayoutBits(
117 const GrPaint& paint,
118 const bool hasTexCoords[GrPaint::kTotalStages]) {
119 int stageMask = paint.getActiveStageMask();
120 int layout = 0;
121 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
122 if ((1 << i) & stageMask) {
123 if (NULL != hasTexCoords && hasTexCoords[i]) {
124 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
125 } else {
126 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
127 }
128 }
129 }
130 return layout;
131}
132
133
134////////////////////////////////////////////////////////////////////////////////
135
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000136enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000137 // flags for textures
138 kNPOTBit = 0x1,
139 kFilterBit = 0x2,
140 kScratchBit = 0x4,
141
142 // resource type
143 kTextureBit = 0x8,
144 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000145};
146
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000147GrTexture* GrContext::TextureCacheEntry::texture() const {
148 if (NULL == fEntry) {
149 return NULL;
150 } else {
151 return (GrTexture*) fEntry->resource();
152 }
153}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000154
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000155namespace {
156// returns true if this is a "special" texture because of gpu NPOT limitations
157bool gen_texture_key_values(const GrGpu* gpu,
158 const GrSamplerState& sampler,
159 GrContext::TextureKey clientKey,
160 int width,
161 int height,
162 bool scratch,
163 uint32_t v[4]) {
164 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
165 // we assume we only need 16 bits of width and height
166 // assert that texture creation will fail anyway if this assumption
167 // would cause key collisions.
168 GrAssert(gpu->maxTextureSize() <= SK_MaxU16);
169 v[0] = clientKey & 0xffffffffUL;
170 v[1] = (clientKey >> 32) & 0xffffffffUL;
171 v[2] = width | (height << 16);
172
173 v[3] = 0;
174 if (!gpu->npotTextureTileSupport()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000175 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
176
177 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
178 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
179
180 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000181 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000182 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000183 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184 }
185 }
186 }
187
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 if (scratch) {
189 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000190 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000192 v[3] |= kTextureBit;
193
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194 return v[3] & kNPOTBit;
195}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000196
197// we should never have more than one stencil buffer with same combo of
198// (width,height,samplecount)
199void gen_stencil_key_values(int width, int height,
200 int sampleCnt, uint32_t v[4]) {
201 v[0] = width;
202 v[1] = height;
203 v[2] = sampleCnt;
204 v[3] = kStencilBufferBit;
205}
206
207void gen_stencil_key_values(const GrStencilBuffer* sb,
208 uint32_t v[4]) {
209 gen_stencil_key_values(sb->width(), sb->height(),
210 sb->numSamples(), v);
211}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000212}
213
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000214GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
215 int width,
216 int height,
217 const GrSamplerState& sampler) {
218 uint32_t v[4];
219 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
220 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000221 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
222 GrResourceCache::kNested_LockType));
223}
224
225GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
226 uint32_t v[4];
227 gen_stencil_key_values(sb, v);
228 GrResourceKey resourceKey(v);
229 return fTextureCache->createAndLock(resourceKey, sb);
230}
231
232GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
233 int sampleCnt) {
234 uint32_t v[4];
235 gen_stencil_key_values(width, height, sampleCnt, v);
236 GrResourceKey resourceKey(v);
237 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
238 GrResourceCache::kSingle_LockType);
239 if (NULL != entry) {
240 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
241 return sb;
242 } else {
243 return NULL;
244 }
245}
246
247void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
248 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000249}
250
251static void stretchImage(void* dst,
252 int dstW,
253 int dstH,
254 void* src,
255 int srcW,
256 int srcH,
257 int bpp) {
258 GrFixed dx = (srcW << 16) / dstW;
259 GrFixed dy = (srcH << 16) / dstH;
260
261 GrFixed y = dy >> 1;
262
263 int dstXLimit = dstW*bpp;
264 for (int j = 0; j < dstH; ++j) {
265 GrFixed x = dx >> 1;
266 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
267 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
268 for (int i = 0; i < dstXLimit; i += bpp) {
269 memcpy((uint8_t*) dstRow + i,
270 (uint8_t*) srcRow + (x>>16)*bpp,
271 bpp);
272 x += dx;
273 }
274 y += dy;
275 }
276}
277
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000278GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000279 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000280 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000281 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000282 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000283
284#if GR_DUMP_TEXTURE_UPLOAD
285 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
286#endif
287
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000288 TextureCacheEntry entry;
289 uint32_t v[4];
290 bool special = gen_texture_key_values(fGpu, sampler, key,
291 desc.fWidth, desc.fHeight, false, v);
292 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000293
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000294 if (special) {
295 TextureCacheEntry clampEntry =
296 findAndLockTexture(key, desc.fWidth, desc.fHeight,
297 GrSamplerState::ClampNoFilter());
298
299 if (NULL == clampEntry.texture()) {
300 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000301 GrSamplerState::ClampNoFilter(),
302 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000303 GrAssert(NULL != clampEntry.texture());
304 if (NULL == clampEntry.texture()) {
305 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000306 }
307 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000308 GrTextureDesc rtDesc = desc;
309 rtDesc.fFlags = rtDesc.fFlags |
310 kRenderTarget_GrTextureFlagBit |
311 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000312 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
313 fGpu->minRenderTargetWidth()));
314 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
315 fGpu->minRenderTargetHeight()));
316
317 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
318
319 if (NULL != texture) {
320 GrDrawTarget::AutoStateRestore asr(fGpu);
321 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000322 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000323 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000324 fGpu->setViewMatrix(GrMatrix::I());
325 fGpu->setAlpha(0xff);
326 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
327 fGpu->disableState(GrDrawTarget::kDither_StateBit |
328 GrDrawTarget::kClip_StateBit |
329 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000330 GrSamplerState::Filter filter;
331 // if filtering is not desired then we want to ensure all
332 // texels in the resampled image are copies of texels from
333 // the original.
334 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
335 filter = GrSamplerState::kNearest_Filter;
336 } else {
337 filter = GrSamplerState::kBilinear_Filter;
338 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000339 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
340 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000341 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000342 fGpu->setSamplerState(0, stretchSampler);
343
344 static const GrVertexLayout layout =
345 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
346 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
347
348 if (arg.succeeded()) {
349 GrPoint* verts = (GrPoint*) arg.vertices();
350 verts[0].setIRectFan(0, 0,
351 texture->width(),
352 texture->height(),
353 2*sizeof(GrPoint));
354 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
355 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
356 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000357 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000358 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000359 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000360 } else {
361 // TODO: Our CPU stretch doesn't filter. But we create separate
362 // stretched textures when the sampler state is either filtered or
363 // not. Either implement filtered stretch blit on CPU or just create
364 // one when FBO case fails.
365
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000366 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000367 // no longer need to clamp at min RT size.
368 rtDesc.fWidth = GrNextPow2(desc.fWidth);
369 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000370 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000371 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000372 rtDesc.fWidth *
373 rtDesc.fHeight);
374 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
375 srcData, desc.fWidth, desc.fHeight, bpp);
376
377 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
378
379 GrTexture* texture = fGpu->createTexture(rtDesc,
380 stretchedPixels.get(),
381 stretchedRowBytes);
382 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000383 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000384 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000385 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000386
387 } else {
388 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
389 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000390 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 }
392 }
393 return entry;
394}
395
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000396namespace {
397inline void gen_scratch_tex_key_values(const GrGpu* gpu,
398 const GrTextureDesc& desc,
399 uint32_t v[4]) {
400 // Instead of a client-provided key of the texture contents
401 // we create a key of from the descriptor.
402 GrContext::TextureKey descKey = desc.fAALevel |
403 (desc.fFlags << 8) |
404 ((uint64_t) desc.fFormat << 32);
405 // this code path isn't friendly to tiling with NPOT restricitons
406 // We just pass ClampNoFilter()
407 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
408 desc.fWidth, desc.fHeight, true, v);
409}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000410}
411
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412GrContext::TextureCacheEntry GrContext::lockScratchTexture(
413 const GrTextureDesc& inDesc,
414 ScratchTexMatch match) {
415
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000416 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000417 if (kExact_ScratchTexMatch != match) {
418 // bin by pow2 with a reasonable min
419 static const int MIN_SIZE = 256;
420 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
421 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
422 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000423
424 uint32_t p0 = desc.fFormat;
425 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
426
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000428 int origWidth = desc.fWidth;
429 int origHeight = desc.fHeight;
430 bool doubledW = false;
431 bool doubledH = false;
432
433 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 uint32_t v[4];
435 gen_scratch_tex_key_values(fGpu, desc, v);
436 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000437 entry = fTextureCache->findAndLock(key,
438 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000439 // if we miss, relax the fit of the flags...
440 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000442 break;
443 }
444 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
445 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
446 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
447 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
448 } else if (!doubledW) {
449 desc.fFlags = inDesc.fFlags;
450 desc.fWidth *= 2;
451 doubledW = true;
452 } else if (!doubledH) {
453 desc.fFlags = inDesc.fFlags;
454 desc.fWidth = origWidth;
455 desc.fHeight *= 2;
456 doubledH = true;
457 } else {
458 break;
459 }
460
461 } while (true);
462
463 if (NULL == entry) {
464 desc.fFlags = inDesc.fFlags;
465 desc.fWidth = origWidth;
466 desc.fHeight = origHeight;
467 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
468 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000469 uint32_t v[4];
470 gen_scratch_tex_key_values(fGpu, desc, v);
471 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000472 entry = fTextureCache->createAndLock(key, texture);
473 }
474 }
475
476 // If the caller gives us the same desc/sampler twice we don't want
477 // to return the same texture the second time (unless it was previously
478 // released). So we detach the entry from the cache and reattach at release.
479 if (NULL != entry) {
480 fTextureCache->detach(entry);
481 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000482 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000483}
484
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485void GrContext::unlockTexture(TextureCacheEntry entry) {
486 // If this is a scratch texture we detached it from the cache
487 // while it was locked (to avoid two callers simultaneously getting
488 // the same texture).
489 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
490 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000491 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000492 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000493 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000494}
495
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000496GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000497 void* srcData,
498 size_t rowBytes) {
499 return fGpu->createTexture(desc, srcData, rowBytes);
500}
501
502void GrContext::getTextureCacheLimits(int* maxTextures,
503 size_t* maxTextureBytes) const {
504 fTextureCache->getLimits(maxTextures, maxTextureBytes);
505}
506
507void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
508 fTextureCache->setLimits(maxTextures, maxTextureBytes);
509}
510
bsalomon@google.com91958362011-06-13 17:58:13 +0000511int GrContext::getMaxTextureSize() const {
512 return fGpu->maxTextureSize();
513}
514
515int GrContext::getMaxRenderTargetSize() const {
516 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000517}
518
519///////////////////////////////////////////////////////////////////////////////
520
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000521GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
522 // validate flags here so that GrGpu subclasses don't have to check
523 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
524 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000525 return NULL;
526 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000527 if (desc.fSampleCnt &&
528 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000529 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000530 }
531 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
532 desc.fSampleCnt &&
533 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
534 return NULL;
535 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000536 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000537}
538
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000539///////////////////////////////////////////////////////////////////////////////
540
bsalomon@google.com27847de2011-02-22 20:59:41 +0000541bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000542 int width, int height) const {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000543 if (!fGpu->supports8BitPalette()) {
544 return false;
545 }
546
547
548 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
549
550 if (!isPow2) {
551 if (!fGpu->npotTextureSupport()) {
552 return false;
553 }
554
555 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
556 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
557 if (tiled && !fGpu->npotTextureTileSupport()) {
558 return false;
559 }
560 }
561 return true;
562}
563
564////////////////////////////////////////////////////////////////////////////////
565
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000566const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
567
bsalomon@google.com27847de2011-02-22 20:59:41 +0000568void GrContext::setClip(const GrClip& clip) {
569 fGpu->setClip(clip);
570 fGpu->enableState(GrDrawTarget::kClip_StateBit);
571}
572
573void GrContext::setClip(const GrIRect& rect) {
574 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000575 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000576 fGpu->setClip(clip);
577}
578
579////////////////////////////////////////////////////////////////////////////////
580
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000581void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000582 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000583 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000584}
585
586void GrContext::drawPaint(const GrPaint& paint) {
587 // set rect to be big enough to fill the space, but not super-huge, so we
588 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000589 GrRect r;
590 r.setLTRB(0, 0,
591 GrIntToScalar(getRenderTarget()->width()),
592 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000593 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000594 GrMatrix inverse;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000595 // We attempt to map r by the inverse matrix and draw that. mapRect will
596 // map the four corners and bound them with a new rect. This will not
597 // produce a correct result for some perspective matrices.
598 if (!this->getMatrix().hasPerspective() &&
599 fGpu->getViewInverse(&inverse)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000600 inverse.mapRect(&r);
601 } else {
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000602 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000603 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000604 GrPaint tmpPaint;
605 const GrPaint* p = &paint;
606 // by definition this fills the entire clip, no need for AA
607 if (paint.fAntiAlias) {
608 tmpPaint = paint;
609 tmpPaint.fAntiAlias = false;
610 p = &tmpPaint;
611 }
612 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000613}
614
bsalomon@google.com205d4602011-04-25 12:43:45 +0000615////////////////////////////////////////////////////////////////////////////////
616
bsalomon@google.com91958362011-06-13 17:58:13 +0000617struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000618 enum Downsample {
619 k4x4TwoPass_Downsample,
620 k4x4SinglePass_Downsample,
621 kFSAA_Downsample
622 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000623 int fTileSizeX;
624 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000625 int fTileCountX;
626 int fTileCountY;
627 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000628 GrAutoScratchTexture fOffscreen0;
629 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000630 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000631 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000632};
633
bsalomon@google.com471d4712011-08-23 15:45:25 +0000634bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000635 const GrPaint& paint,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000636 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000637#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000638 return false;
639#else
640 if (!paint.fAntiAlias) {
641 return false;
642 }
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000643 // Line primitves are always rasterized as 1 pixel wide.
644 // Super-sampling would make them too thin but MSAA would be OK.
645 if (isHairLines &&
646 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA())) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000647 return false;
648 }
649 if (target->getRenderTarget()->isMultisampled()) {
650 return false;
651 }
652 // we have to be sure that the blend equation is expressible
653 // as simple src / dst coeffecients when the source
654 // is already modulated by the coverage fraction.
655 // We could use dual-source blending to get the correct per-pixel
656 // dst coeffecient for the remaining cases.
657 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
658 kOne_BlendCoeff != paint.fDstBlendCoeff &&
659 kISA_BlendCoeff != paint.fDstBlendCoeff) {
660 return false;
661 }
662 return true;
663#endif
664}
665
bsalomon@google.com91958362011-06-13 17:58:13 +0000666bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000667 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000668 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000669 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000670 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000671
672 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000673
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000674 GrAssert(NULL == record->fOffscreen0.texture());
675 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000676 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000677
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000678 int boundW = boundRect.width();
679 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000680
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000681 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000682
683 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
684 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
685
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000686 if (requireStencil) {
687 desc.fFlags = kRenderTarget_GrTextureFlagBit;
688 } else {
689 desc.fFlags = kRenderTarget_GrTextureFlagBit |
690 kNoStencil_GrTextureFlagBit;
691 }
692
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000693 desc.fFormat = kRGBA_8888_GrPixelConfig;
694
bsalomon@google.com91958362011-06-13 17:58:13 +0000695 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000696 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000697 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000698 desc.fAALevel = kMed_GrAALevel;
699 } else {
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000700 record->fDownsample = (fGpu->supportsShaders()) ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000701 OffscreenRecord::k4x4SinglePass_Downsample :
702 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000703 record->fScale = OFFSCREEN_SSAA_SCALE;
704 // both downsample paths assume this
705 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000706 desc.fAALevel = kNone_GrAALevel;
707 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000708
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000709 desc.fWidth *= record->fScale;
710 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000711 record->fOffscreen0.set(this, desc);
712 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000713 return false;
714 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000715 // the approximate lookup might have given us some slop space, might as well
716 // use it when computing the tiles size.
717 // these are scale values, will adjust after considering
718 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000719 record->fTileSizeX = record->fOffscreen0.texture()->width();
720 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000721
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000722 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000723 desc.fWidth /= 2;
724 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000725 record->fOffscreen1.set(this, desc);
726 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000727 return false;
728 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000729 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000730 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000731 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000732 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000733 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000734 record->fTileSizeX /= record->fScale;
735 record->fTileSizeY /= record->fScale;
736
737 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
738 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
739
tomhudson@google.com237a4612011-07-19 15:44:00 +0000740 record->fClip = target->getClip();
741
bsalomon@google.com91958362011-06-13 17:58:13 +0000742 target->saveCurrentDrawState(&record->fSavedState);
743 return true;
744}
745
746void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
747 const GrIRect& boundRect,
748 int tileX, int tileY,
749 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000750
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000751 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000752 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000753
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000754 GrPaint tempPaint;
755 tempPaint.reset();
756 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000757 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000758
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000759 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000760 int left = boundRect.fLeft + tileX * record->fTileSizeX;
761 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000762 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000763 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000764 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000765 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000766 target->postConcatViewMatrix(scaleM);
767
bsalomon@google.com91958362011-06-13 17:58:13 +0000768 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000769 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000770 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000771 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000772 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
773 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000774 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000775#if 0
776 // visualize tile boundaries by setting edges of offscreen to white
777 // and interior to tranparent. black.
778 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000779
bsalomon@google.com91958362011-06-13 17:58:13 +0000780 static const int gOffset = 2;
781 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
782 record->fScale * w - gOffset,
783 record->fScale * h - gOffset);
784 target->clear(&clear2, 0x0);
785#else
786 target->clear(&clear, 0x0);
787#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000788}
789
bsalomon@google.com91958362011-06-13 17:58:13 +0000790void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000791 const GrPaint& paint,
792 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000793 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000794 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000795 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000796 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000797 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000798 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000799 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
800 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000801 tileRect.fRight = (tileX == record->fTileCountX-1) ?
802 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000803 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000804 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
805 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000806 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000807
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000808 GrSamplerState::Filter filter;
809 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
810 filter = GrSamplerState::k4x4Downsample_Filter;
811 } else {
812 filter = GrSamplerState::kBilinear_Filter;
813 }
814
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000815 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000816 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000817 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000818
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000819 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000820 int scale;
821
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000822 enum {
823 kOffscreenStage = GrPaint::kTotalStages,
824 };
825
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000826 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000827 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000828 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000829 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000830
831 // Do 2x2 downsample from first to second
832 target->setTexture(kOffscreenStage, src);
833 target->setRenderTarget(dst);
834 target->setViewMatrix(GrMatrix::I());
835 sampleM.setScale(scale * GR_Scalar1 / src->width(),
836 scale * GR_Scalar1 / src->height());
837 sampler.setMatrix(sampleM);
838 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000839 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
840 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000841 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
842
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000843 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000844 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000845 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000846 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000847 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000848 } else {
849 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
850 record->fDownsample);
851 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000852 }
853
bsalomon@google.com91958362011-06-13 17:58:13 +0000854 // setup for draw back to main RT, we use the original
855 // draw state setup by the caller plus an additional coverage
856 // stage to handle the AA resolve. Also, we use an identity
857 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000858 int stageMask = paint.getActiveStageMask();
859
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000860 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000861 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000862
863 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 GrMatrix invVM;
865 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000866 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000867 }
868 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000869 // This is important when tiling, otherwise second tile's
870 // pass 1 view matrix will be incorrect.
871 GrDrawTarget::AutoViewMatrixRestore avmr(target);
872
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000873 target->setViewMatrix(GrMatrix::I());
874
875 target->setTexture(kOffscreenStage, src);
876 sampleM.setScale(scale * GR_Scalar1 / src->width(),
877 scale * GR_Scalar1 / src->height());
878 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000879 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000880 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000881 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000882
reed@google.com20efde72011-05-09 17:00:02 +0000883 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000884 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000885 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000886 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000887}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000888
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000889void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
890 GrPathRenderer* pr,
891 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000892 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000893}
894
895////////////////////////////////////////////////////////////////////////////////
896
bsalomon@google.com27847de2011-02-22 20:59:41 +0000897/* create a triangle strip that strokes the specified triangle. There are 8
898 unique vertices, but we repreat the last 2 to close up. Alternatively we
899 could use an indices array, and then only send 8 verts, but not sure that
900 would be faster.
901 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000902static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000903 GrScalar width) {
904 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000905 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000906
907 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
908 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
909 verts[2].set(rect.fRight - rad, rect.fTop + rad);
910 verts[3].set(rect.fRight + rad, rect.fTop - rad);
911 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
912 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
913 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
914 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
915 verts[8] = verts[0];
916 verts[9] = verts[1];
917}
918
bsalomon@google.com205d4602011-04-25 12:43:45 +0000919static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000920 // FIXME: This was copied from SkGpuDevice, seems like
921 // we should have already smeared a in caller if that
922 // is what is desired.
923 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000924 unsigned a = GrColorUnpackA(paint.fColor);
925 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000926 } else {
927 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000928 }
929}
930
931static void setInsetFan(GrPoint* pts, size_t stride,
932 const GrRect& r, GrScalar dx, GrScalar dy) {
933 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
934}
935
936static const uint16_t gFillAARectIdx[] = {
937 0, 1, 5, 5, 4, 0,
938 1, 2, 6, 6, 5, 1,
939 2, 3, 7, 7, 6, 2,
940 3, 0, 4, 4, 7, 3,
941 4, 5, 6, 6, 7, 4,
942};
943
944int GrContext::aaFillRectIndexCount() const {
945 return GR_ARRAY_COUNT(gFillAARectIdx);
946}
947
948GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
949 if (NULL == fAAFillRectIndexBuffer) {
950 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
951 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000952 if (NULL != fAAFillRectIndexBuffer) {
953 #if GR_DEBUG
954 bool updated =
955 #endif
956 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
957 sizeof(gFillAARectIdx));
958 GR_DEBUGASSERT(updated);
959 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000960 }
961 return fAAFillRectIndexBuffer;
962}
963
964static const uint16_t gStrokeAARectIdx[] = {
965 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
966 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
967 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
968 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
969
970 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
971 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
972 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
973 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
974
975 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
976 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
977 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
978 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
979};
980
981int GrContext::aaStrokeRectIndexCount() const {
982 return GR_ARRAY_COUNT(gStrokeAARectIdx);
983}
984
985GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
986 if (NULL == fAAStrokeRectIndexBuffer) {
987 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
988 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000989 if (NULL != fAAStrokeRectIndexBuffer) {
990 #if GR_DEBUG
991 bool updated =
992 #endif
993 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
994 sizeof(gStrokeAARectIdx));
995 GR_DEBUGASSERT(updated);
996 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000997 }
998 return fAAStrokeRectIndexBuffer;
999}
1000
1001void GrContext::fillAARect(GrDrawTarget* target,
1002 const GrPaint& paint,
1003 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001004 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1005 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001006
1007 size_t vsize = GrDrawTarget::VertexSize(layout);
1008
1009 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001010 if (!geo.succeeded()) {
1011 GrPrintf("Failed to get space for vertices!\n");
1012 return;
1013 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001014 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1015 if (NULL == indexBuffer) {
1016 GrPrintf("Failed to create index buffer!\n");
1017 return;
1018 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001019
1020 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1021
1022 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1023 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1024
1025 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1026 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1027
1028 verts += sizeof(GrPoint);
1029 for (int i = 0; i < 4; ++i) {
1030 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1031 }
1032
1033 GrColor innerColor = getColorForMesh(paint);
1034 verts += 4 * vsize;
1035 for (int i = 0; i < 4; ++i) {
1036 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1037 }
1038
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001039 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001040
1041 target->drawIndexed(kTriangles_PrimitiveType, 0,
1042 0, 8, this->aaFillRectIndexCount());
1043}
1044
1045void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
1046 const GrRect& devRect, const GrVec& devStrokeSize) {
1047 const GrScalar& dx = devStrokeSize.fX;
1048 const GrScalar& dy = devStrokeSize.fY;
1049 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1050 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1051
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001052 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
1053 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +00001054
1055 GrScalar spare;
1056 {
1057 GrScalar w = devRect.width() - dx;
1058 GrScalar h = devRect.height() - dy;
1059 spare = GrMin(w, h);
1060 }
1061
1062 if (spare <= 0) {
1063 GrRect r(devRect);
1064 r.inset(-rx, -ry);
1065 fillAARect(target, paint, r);
1066 return;
1067 }
1068
1069 size_t vsize = GrDrawTarget::VertexSize(layout);
1070
1071 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001072 if (!geo.succeeded()) {
1073 GrPrintf("Failed to get space for vertices!\n");
1074 return;
1075 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001076 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1077 if (NULL == indexBuffer) {
1078 GrPrintf("Failed to create index buffer!\n");
1079 return;
1080 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001081
1082 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1083
1084 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1085 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1086 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1087 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1088
1089 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1090 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1091 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1092 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1093
1094 verts += sizeof(GrPoint);
1095 for (int i = 0; i < 4; ++i) {
1096 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1097 }
1098
1099 GrColor innerColor = getColorForMesh(paint);
1100 verts += 4 * vsize;
1101 for (int i = 0; i < 8; ++i) {
1102 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1103 }
1104
1105 verts += 8 * vsize;
1106 for (int i = 0; i < 8; ++i) {
1107 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1108 }
1109
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001110 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001111 target->drawIndexed(kTriangles_PrimitiveType,
1112 0, 0, 16, aaStrokeRectIndexCount());
1113}
1114
reed@google.com20efde72011-05-09 17:00:02 +00001115/**
1116 * Returns true if the rects edges are integer-aligned.
1117 */
1118static bool isIRect(const GrRect& r) {
1119 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1120 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1121}
1122
bsalomon@google.com205d4602011-04-25 12:43:45 +00001123static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001124 const GrPaint& paint,
1125 const GrRect& rect,
1126 GrScalar width,
1127 const GrMatrix* matrix,
1128 GrMatrix* combinedMatrix,
1129 GrRect* devRect) {
1130 // we use a simple alpha ramp to do aa on axis-aligned rects
1131 // do AA with alpha ramp if the caller requested AA, the rect
1132 // will be axis-aligned,the render target is not
1133 // multisampled, and the rect won't land on integer coords.
1134
1135 if (!paint.fAntiAlias) {
1136 return false;
1137 }
1138
1139 if (target->getRenderTarget()->isMultisampled()) {
1140 return false;
1141 }
1142
bsalomon@google.com471d4712011-08-23 15:45:25 +00001143 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001144 return false;
1145 }
1146
1147 if (!target->getViewMatrix().preservesAxisAlignment()) {
1148 return false;
1149 }
1150
1151 if (NULL != matrix &&
1152 !matrix->preservesAxisAlignment()) {
1153 return false;
1154 }
1155
1156 *combinedMatrix = target->getViewMatrix();
1157 if (NULL != matrix) {
1158 combinedMatrix->preConcat(*matrix);
1159 GrAssert(combinedMatrix->preservesAxisAlignment());
1160 }
1161
1162 combinedMatrix->mapRect(devRect, rect);
1163 devRect->sort();
1164
1165 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001166 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001167 } else {
1168 return true;
1169 }
1170}
1171
bsalomon@google.com27847de2011-02-22 20:59:41 +00001172void GrContext::drawRect(const GrPaint& paint,
1173 const GrRect& rect,
1174 GrScalar width,
1175 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001176 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001177
1178 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001179 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001180
bsalomon@google.com205d4602011-04-25 12:43:45 +00001181 GrRect devRect = rect;
1182 GrMatrix combinedMatrix;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001183 bool doAA = apply_aa_to_rect(target, paint, rect, width, matrix,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001184 &combinedMatrix, &devRect);
1185
1186 if (doAA) {
1187 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001188 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001189 GrMatrix inv;
1190 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001191 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001192 }
1193 }
1194 target->setViewMatrix(GrMatrix::I());
1195 if (width >= 0) {
1196 GrVec strokeSize;;
1197 if (width > 0) {
1198 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001199 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001200 strokeSize.setAbs(strokeSize);
1201 } else {
1202 strokeSize.set(GR_Scalar1, GR_Scalar1);
1203 }
1204 strokeAARect(target, paint, devRect, strokeSize);
1205 } else {
1206 fillAARect(target, paint, devRect);
1207 }
1208 return;
1209 }
1210
bsalomon@google.com27847de2011-02-22 20:59:41 +00001211 if (width >= 0) {
1212 // TODO: consider making static vertex buffers for these cases.
1213 // Hairline could be done by just adding closing vertex to
1214 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001215 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1216
bsalomon@google.com27847de2011-02-22 20:59:41 +00001217 static const int worstCaseVertCount = 10;
1218 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1219
1220 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001221 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001222 return;
1223 }
1224
1225 GrPrimitiveType primType;
1226 int vertCount;
1227 GrPoint* vertex = geo.positions();
1228
1229 if (width > 0) {
1230 vertCount = 10;
1231 primType = kTriangleStrip_PrimitiveType;
1232 setStrokeRectStrip(vertex, rect, width);
1233 } else {
1234 // hairline
1235 vertCount = 5;
1236 primType = kLineStrip_PrimitiveType;
1237 vertex[0].set(rect.fLeft, rect.fTop);
1238 vertex[1].set(rect.fRight, rect.fTop);
1239 vertex[2].set(rect.fRight, rect.fBottom);
1240 vertex[3].set(rect.fLeft, rect.fBottom);
1241 vertex[4].set(rect.fLeft, rect.fTop);
1242 }
1243
1244 GrDrawTarget::AutoViewMatrixRestore avmr;
1245 if (NULL != matrix) {
1246 avmr.set(target);
1247 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001248 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001249 }
1250
1251 target->drawNonIndexed(primType, 0, vertCount);
1252 } else {
1253 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001254 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001255 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1256 if (NULL == sqVB) {
1257 GrPrintf("Failed to create static rect vb.\n");
1258 return;
1259 }
1260 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001261 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1262 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001263 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001264 0, rect.height(), rect.fTop,
1265 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001266
1267 if (NULL != matrix) {
1268 m.postConcat(*matrix);
1269 }
1270
1271 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001272 target->preConcatSamplerMatrices(stageMask, m);
1273
bsalomon@google.com27847de2011-02-22 20:59:41 +00001274 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1275 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001276 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001277 #endif
1278 }
1279}
1280
1281void GrContext::drawRectToRect(const GrPaint& paint,
1282 const GrRect& dstRect,
1283 const GrRect& srcRect,
1284 const GrMatrix* dstMatrix,
1285 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001286 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001288 // srcRect refers to paint's first texture
1289 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001290 drawRect(paint, dstRect, -1, dstMatrix);
1291 return;
1292 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001293
bsalomon@google.com27847de2011-02-22 20:59:41 +00001294 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1295
1296#if GR_STATIC_RECT_VB
1297 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001298
1299 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1301
1302 GrMatrix m;
1303
1304 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1305 0, dstRect.height(), dstRect.fTop,
1306 0, 0, GrMatrix::I()[8]);
1307 if (NULL != dstMatrix) {
1308 m.postConcat(*dstMatrix);
1309 }
1310 target->preConcatViewMatrix(m);
1311
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001312 // srcRect refers to first stage
1313 int otherStageMask = paint.getActiveStageMask() &
1314 (~(1 << GrPaint::kFirstTextureStage));
1315 if (otherStageMask) {
1316 target->preConcatSamplerMatrices(otherStageMask, m);
1317 }
1318
bsalomon@google.com27847de2011-02-22 20:59:41 +00001319 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1320 0, srcRect.height(), srcRect.fTop,
1321 0, 0, GrMatrix::I()[8]);
1322 if (NULL != srcMatrix) {
1323 m.postConcat(*srcMatrix);
1324 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001325 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001327 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1328 if (NULL == sqVB) {
1329 GrPrintf("Failed to create static rect vb.\n");
1330 return;
1331 }
1332 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001333 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1334#else
1335
1336 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001337#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001338 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001339#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001340 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1341#endif
1342
1343 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1344 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1345 srcRects[0] = &srcRect;
1346 srcMatrices[0] = srcMatrix;
1347
1348 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1349#endif
1350}
1351
1352void GrContext::drawVertices(const GrPaint& paint,
1353 GrPrimitiveType primitiveType,
1354 int vertexCount,
1355 const GrPoint positions[],
1356 const GrPoint texCoords[],
1357 const GrColor colors[],
1358 const uint16_t indices[],
1359 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001360 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001361
1362 GrDrawTarget::AutoReleaseGeometry geo;
1363
1364 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1365
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001366 bool hasTexCoords[GrPaint::kTotalStages] = {
1367 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1368 0 // remaining stages use positions
1369 };
1370
1371 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372
1373 if (NULL != colors) {
1374 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001375 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001376 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377
1378 if (sizeof(GrPoint) != vertexSize) {
1379 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001380 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001381 return;
1382 }
1383 int texOffsets[GrDrawTarget::kMaxTexCoords];
1384 int colorOffset;
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001385 int edgeOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001386 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1387 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001388 &colorOffset,
1389 &edgeOffset);
1390 GrAssert(-1 == edgeOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001391 void* curVertex = geo.vertices();
1392
1393 for (int i = 0; i < vertexCount; ++i) {
1394 *((GrPoint*)curVertex) = positions[i];
1395
1396 if (texOffsets[0] > 0) {
1397 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1398 }
1399 if (colorOffset > 0) {
1400 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1401 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001402 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001403 }
1404 } else {
1405 target->setVertexSourceToArray(layout, positions, vertexCount);
1406 }
1407
bsalomon@google.com91958362011-06-13 17:58:13 +00001408 // we don't currently apply offscreen AA to this path. Need improved
1409 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001410
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001411 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001412 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001413 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001414 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001415 target->drawNonIndexed(primitiveType, 0, vertexCount);
1416 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417}
1418
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001419///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420
reed@google.com07f3ee12011-05-16 17:21:57 +00001421void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1422 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423
bsalomon@google.com27847de2011-02-22 20:59:41 +00001424 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com30085192011-08-19 15:42:31 +00001425 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
1426 if (NULL == pr) {
1427 GrPrintf("Unable to find path renderer compatible with path.\n");
1428 return;
1429 }
1430
bsalomon@google.comee435122011-07-01 14:57:55 +00001431 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1432 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001433
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001434 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001435 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001436
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001437 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001438
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001439 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001440 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1441 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001442 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001443 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001444 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001445 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001446 return;
1447 }
1448 }
reed@google.com70c136e2011-06-03 19:51:26 +00001449
reed@google.com07f3ee12011-05-16 17:21:57 +00001450 GrRect pathBounds = path.getBounds();
1451 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001452 if (NULL != translate) {
1453 pathBounds.offset(*translate);
1454 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001455 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001456 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001457 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001458 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001459 return;
1460 }
1461 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001462 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001463 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1464 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001465 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1466 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1467 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001468 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001469 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1470 }
1471 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001472 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001473 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001474 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1475 GrRect rect;
1476 if (clipIBounds.fTop < bound.fTop) {
1477 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1478 clipIBounds.fRight, bound.fTop);
1479 target->drawSimpleRect(rect, NULL, stageMask);
1480 }
1481 if (clipIBounds.fLeft < bound.fLeft) {
1482 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1483 bound.fLeft, bound.fBottom);
1484 target->drawSimpleRect(rect, NULL, stageMask);
1485 }
1486 if (clipIBounds.fRight > bound.fRight) {
1487 rect.setLTRB(bound.fRight, bound.fTop,
1488 clipIBounds.fRight, bound.fBottom);
1489 target->drawSimpleRect(rect, NULL, stageMask);
1490 }
1491 if (clipIBounds.fBottom > bound.fBottom) {
1492 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1493 clipIBounds.fRight, clipIBounds.fBottom);
1494 target->drawSimpleRect(rect, NULL, stageMask);
1495 }
1496 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001497 return;
1498 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001499 }
1500 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001501}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001502
bsalomon@google.com27847de2011-02-22 20:59:41 +00001503////////////////////////////////////////////////////////////////////////////////
1504
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001505bool GrContext::supportsShaders() const {
1506 return fGpu->supportsShaders();
1507}
1508
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001509void GrContext::flush(int flagsBitfield) {
1510 if (kDiscard_FlushBit & flagsBitfield) {
1511 fDrawBuffer->reset();
1512 } else {
1513 flushDrawBuffer();
1514 }
1515
1516 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001517 fGpu->forceRenderTargetFlush();
1518 }
1519}
1520
1521void GrContext::flushText() {
1522 if (kText_DrawCategory == fLastDrawCategory) {
1523 flushDrawBuffer();
1524 }
1525}
1526
1527void GrContext::flushDrawBuffer() {
1528#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001529 if (fDrawBuffer) {
1530 fDrawBuffer->playback(fGpu);
1531 fDrawBuffer->reset();
1532 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001533#endif
1534}
1535
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001536bool GrContext::readTexturePixels(GrTexture* texture,
1537 int left, int top, int width, int height,
1538 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001539 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001540
1541 // TODO: code read pixels for textures that aren't rendertargets
1542
1543 this->flush();
1544 GrRenderTarget* target = texture->asRenderTarget();
1545 if (NULL != target) {
1546 return fGpu->readPixels(target,
1547 left, top, width, height,
1548 config, buffer);
1549 } else {
1550 return false;
1551 }
1552}
1553
1554bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1555 int left, int top, int width, int height,
1556 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001557 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001558 uint32_t flushFlags = 0;
1559 if (NULL == target) {
1560 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1561 }
1562
1563 this->flush(flushFlags);
1564 return fGpu->readPixels(target,
1565 left, top, width, height,
1566 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001567}
1568
1569void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001570 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001571 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001572 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001573
1574 // TODO: when underlying api has a direct way to do this we should use it
1575 // (e.g. glDrawPixels on desktop GL).
1576
bsalomon@google.com5c638652011-07-18 19:31:59 +00001577 this->flush(true);
1578
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001579 const GrTextureDesc desc = {
1580 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001581 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001582 GrAutoScratchTexture ast(this, desc);
1583 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001584 if (NULL == texture) {
1585 return;
1586 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001587 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001588
bsalomon@google.com27847de2011-02-22 20:59:41 +00001589 GrDrawTarget::AutoStateRestore asr(fGpu);
1590
1591 GrMatrix matrix;
1592 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1593 fGpu->setViewMatrix(matrix);
1594
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001595 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001596 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1597 fGpu->setAlpha(0xFF);
1598 fGpu->setBlendFunc(kOne_BlendCoeff,
1599 kZero_BlendCoeff);
1600 fGpu->setTexture(0, texture);
1601
1602 GrSamplerState sampler;
1603 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001604 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001605 sampler.setMatrix(matrix);
1606 fGpu->setSamplerState(0, sampler);
1607
1608 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1609 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001610 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001611 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1612 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001613 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614 return;
1615 }
1616 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1617 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1618}
1619////////////////////////////////////////////////////////////////////////////////
1620
1621void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001622
1623 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1624 int s = i + GrPaint::kFirstTextureStage;
1625 target->setTexture(s, paint.getTexture(i));
1626 target->setSamplerState(s, *paint.getTextureSampler(i));
1627 }
1628
1629 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1630
1631 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1632 int s = i + GrPaint::kFirstMaskStage;
1633 target->setTexture(s, paint.getMask(i));
1634 target->setSamplerState(s, *paint.getMaskSampler(i));
1635 }
1636
bsalomon@google.com27847de2011-02-22 20:59:41 +00001637 target->setColor(paint.fColor);
1638
1639 if (paint.fDither) {
1640 target->enableState(GrDrawTarget::kDither_StateBit);
1641 } else {
1642 target->disableState(GrDrawTarget::kDither_StateBit);
1643 }
1644 if (paint.fAntiAlias) {
1645 target->enableState(GrDrawTarget::kAntialias_StateBit);
1646 } else {
1647 target->disableState(GrDrawTarget::kAntialias_StateBit);
1648 }
1649 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001650 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001651}
1652
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001653GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001654 DrawCategory category) {
1655 if (category != fLastDrawCategory) {
1656 flushDrawBuffer();
1657 fLastDrawCategory = category;
1658 }
1659 SetPaint(paint, fGpu);
1660 GrDrawTarget* target = fGpu;
1661 switch (category) {
1662 case kText_DrawCategory:
1663#if DEFER_TEXT_RENDERING
1664 target = fDrawBuffer;
1665 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1666#else
1667 target = fGpu;
1668#endif
1669 break;
1670 case kUnbuffered_DrawCategory:
1671 target = fGpu;
1672 break;
1673 case kBuffered_DrawCategory:
1674 target = fDrawBuffer;
1675 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1676 break;
1677 }
1678 return target;
1679}
1680
bsalomon@google.com30085192011-08-19 15:42:31 +00001681GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1682 const GrPath& path,
1683 GrPathFill fill) {
1684 if (NULL == fPathRendererChain) {
1685 fPathRendererChain =
1686 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1687 }
1688 return fPathRendererChain->getPathRenderer(target, path, fill);
1689}
1690
bsalomon@google.com27847de2011-02-22 20:59:41 +00001691////////////////////////////////////////////////////////////////////////////////
1692
bsalomon@google.com27847de2011-02-22 20:59:41 +00001693void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001694 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001695 fGpu->setRenderTarget(target);
1696}
1697
1698GrRenderTarget* GrContext::getRenderTarget() {
1699 return fGpu->getRenderTarget();
1700}
1701
1702const GrRenderTarget* GrContext::getRenderTarget() const {
1703 return fGpu->getRenderTarget();
1704}
1705
1706const GrMatrix& GrContext::getMatrix() const {
1707 return fGpu->getViewMatrix();
1708}
1709
1710void GrContext::setMatrix(const GrMatrix& m) {
1711 fGpu->setViewMatrix(m);
1712}
1713
1714void GrContext::concatMatrix(const GrMatrix& m) const {
1715 fGpu->preConcatViewMatrix(m);
1716}
1717
1718static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1719 intptr_t mask = 1 << shift;
1720 if (pred) {
1721 bits |= mask;
1722 } else {
1723 bits &= ~mask;
1724 }
1725 return bits;
1726}
1727
1728void GrContext::resetStats() {
1729 fGpu->resetStats();
1730}
1731
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001732const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001733 return fGpu->getStats();
1734}
1735
1736void GrContext::printStats() const {
1737 fGpu->printStats();
1738}
1739
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001740GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001741 fGpu = gpu;
1742 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001743 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001744
bsalomon@google.com30085192011-08-19 15:42:31 +00001745 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001746
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001747 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1748 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001749 fFontCache = new GrFontCache(fGpu);
1750
1751 fLastDrawCategory = kUnbuffered_DrawCategory;
1752
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001753 fDrawBuffer = NULL;
1754 fDrawBufferVBAllocPool = NULL;
1755 fDrawBufferIBAllocPool = NULL;
1756
bsalomon@google.com205d4602011-04-25 12:43:45 +00001757 fAAFillRectIndexBuffer = NULL;
1758 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001759
1760 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1761 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1762 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1763 }
1764 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001765
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001766 this->setupDrawBuffer();
1767}
1768
1769void GrContext::setupDrawBuffer() {
1770
1771 GrAssert(NULL == fDrawBuffer);
1772 GrAssert(NULL == fDrawBufferVBAllocPool);
1773 GrAssert(NULL == fDrawBufferIBAllocPool);
1774
bsalomon@google.com27847de2011-02-22 20:59:41 +00001775#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001776 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001777 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001778 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1779 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001780 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001781 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001782 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001783 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1784
bsalomon@google.com471d4712011-08-23 15:45:25 +00001785 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1786 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001787 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001788#endif
1789
1790#if BATCH_RECT_TO_RECT
1791 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1792#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001793}
1794
bsalomon@google.com27847de2011-02-22 20:59:41 +00001795GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1796 GrDrawTarget* target;
1797#if DEFER_TEXT_RENDERING
1798 target = prepareToDraw(paint, kText_DrawCategory);
1799#else
1800 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1801#endif
1802 SetPaint(paint, target);
1803 return target;
1804}
1805
1806const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1807 return fGpu->getQuadIndexBuffer();
1808}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001809
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001810void GrContext::convolveInX(GrTexture* texture,
1811 const SkRect& rect,
1812 const float* kernel,
1813 int kernelWidth) {
1814 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1815 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1816}
1817
1818void GrContext::convolveInY(GrTexture* texture,
1819 const SkRect& rect,
1820 const float* kernel,
1821 int kernelWidth) {
1822 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1823 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1824}
1825
1826void GrContext::convolve(GrTexture* texture,
1827 const SkRect& rect,
1828 float imageIncrement[2],
1829 const float* kernel,
1830 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001831 GrDrawTarget::AutoStateRestore asr(fGpu);
1832 GrMatrix sampleM;
1833 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1834 GrSamplerState::kClamp_WrapMode,
1835 GrSamplerState::kConvolution_Filter);
1836 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001837 sampleM.setScale(GR_Scalar1 / texture->width(),
1838 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001839 sampler.setMatrix(sampleM);
1840 fGpu->setSamplerState(0, sampler);
1841 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001842 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001843 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001844 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1845}