blob: 74ed582e2ade6ff111fba32943c0022fa5b0909b [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000021#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000022#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023
bsalomon@google.com91958362011-06-13 17:58:13 +000024// Using MSAA seems to be slower for some yet unknown reason.
25#define PREFER_MSAA_OFFSCREEN_AA 0
26#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000027
bsalomon@google.com27847de2011-02-22 20:59:41 +000028#define DEFER_TEXT_RENDERING 1
29
30#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
bsalomon@google.comd46e2422011-09-23 17:40:07 +000032// When we're using coverage AA but the blend is incompatible (given gpu
33// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000034#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000035
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000036static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
37static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000038
39static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
40static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
41
42// We are currently only batching Text and drawRectToRect, both
43// of which use the quad index buffer.
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
46
bsalomon@google.com05ef5102011-05-02 21:14:59 +000047GrContext* GrContext::Create(GrEngine engine,
48 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000049 GrContext* ctx = NULL;
50 GrGpu* fGpu = GrGpu::Create(engine, context3D);
51 if (NULL != fGpu) {
52 ctx = new GrContext(fGpu);
53 fGpu->unref();
54 }
55 return ctx;
56}
57
58GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000059 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000060}
61
62GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000063 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000064 delete fTextureCache;
65 delete fFontCache;
66 delete fDrawBuffer;
67 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000068 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000069
bsalomon@google.com205d4602011-04-25 12:43:45 +000070 GrSafeUnref(fAAFillRectIndexBuffer);
71 GrSafeUnref(fAAStrokeRectIndexBuffer);
72 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000073 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com30085192011-08-19 15:42:31 +000086 // a path renderer may be holding onto resources that
87 // are now unusable
88 GrSafeSetNull(fPathRendererChain);
89
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 delete fDrawBuffer;
91 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000092
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 delete fDrawBufferVBAllocPool;
94 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000095
bsalomon@google.com8fe72472011-03-30 21:26:44 +000096 delete fDrawBufferIBAllocPool;
97 fDrawBufferIBAllocPool = NULL;
98
bsalomon@google.com205d4602011-04-25 12:43:45 +000099 GrSafeSetNull(fAAFillRectIndexBuffer);
100 GrSafeSetNull(fAAStrokeRectIndexBuffer);
101
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102 fTextureCache->removeAll();
103 fFontCache->freeAll();
104 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000105}
106
107void GrContext::resetContext() {
108 fGpu->markContextDirty();
109}
110
111void GrContext::freeGpuResources() {
112 this->flush();
113 fTextureCache->removeAll();
114 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000115 // a path renderer may be holding onto resources
116 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000117}
118
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000119////////////////////////////////////////////////////////////////////////////////
120
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000121int GrContext::PaintStageVertexLayoutBits(
122 const GrPaint& paint,
123 const bool hasTexCoords[GrPaint::kTotalStages]) {
124 int stageMask = paint.getActiveStageMask();
125 int layout = 0;
126 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
127 if ((1 << i) & stageMask) {
128 if (NULL != hasTexCoords && hasTexCoords[i]) {
129 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
130 } else {
131 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
132 }
133 }
134 }
135 return layout;
136}
137
138
139////////////////////////////////////////////////////////////////////////////////
140
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000141enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000142 // flags for textures
143 kNPOTBit = 0x1,
144 kFilterBit = 0x2,
145 kScratchBit = 0x4,
146
147 // resource type
148 kTextureBit = 0x8,
149 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000150};
151
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000152GrTexture* GrContext::TextureCacheEntry::texture() const {
153 if (NULL == fEntry) {
154 return NULL;
155 } else {
156 return (GrTexture*) fEntry->resource();
157 }
158}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000159
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000160namespace {
161// returns true if this is a "special" texture because of gpu NPOT limitations
162bool gen_texture_key_values(const GrGpu* gpu,
163 const GrSamplerState& sampler,
164 GrContext::TextureKey clientKey,
165 int width,
166 int height,
167 bool scratch,
168 uint32_t v[4]) {
169 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
170 // we assume we only need 16 bits of width and height
171 // assert that texture creation will fail anyway if this assumption
172 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000173 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000174 v[0] = clientKey & 0xffffffffUL;
175 v[1] = (clientKey >> 32) & 0xffffffffUL;
176 v[2] = width | (height << 16);
177
178 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000179 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000180 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
181
182 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
183 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
184
185 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000187 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 }
190 }
191 }
192
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 if (scratch) {
194 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197 v[3] |= kTextureBit;
198
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199 return v[3] & kNPOTBit;
200}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000201
202// we should never have more than one stencil buffer with same combo of
203// (width,height,samplecount)
204void gen_stencil_key_values(int width, int height,
205 int sampleCnt, uint32_t v[4]) {
206 v[0] = width;
207 v[1] = height;
208 v[2] = sampleCnt;
209 v[3] = kStencilBufferBit;
210}
211
212void gen_stencil_key_values(const GrStencilBuffer* sb,
213 uint32_t v[4]) {
214 gen_stencil_key_values(sb->width(), sb->height(),
215 sb->numSamples(), v);
216}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000217
218// This should be subsumed by a future version of GrDrawState
219// It does not reset stage textures/samplers or per-vertex-edge-aa state since
220// they aren't used unless the vertex layout references them.
221// It also doesn't set the render target.
222void reset_target_state(GrDrawTarget* target){
223 target->setViewMatrix(GrMatrix::I());
224 target->setColorFilter(0, SkXfermode::kDst_Mode);
225 target->disableState(GrDrawTarget::kDither_StateBit |
226 GrDrawTarget::kHWAntialias_StateBit |
227 GrDrawTarget::kClip_StateBit |
228 GrDrawTarget::kNoColorWrites_StateBit |
229 GrDrawTarget::kEdgeAAConcave_StateBit);
230 target->setEdgeAAData(NULL, 0);
231 target->disableStencil();
232 target->setAlpha(0xFF);
233 target->setBlendFunc(kOne_BlendCoeff,
234 kZero_BlendCoeff);
235 target->setFirstCoverageStage(GrDrawState::kNumStages);
236 target->setDrawFace(GrDrawState::kBoth_DrawFace);
237}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000238}
239
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000240GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
241 int width,
242 int height,
243 const GrSamplerState& sampler) {
244 uint32_t v[4];
245 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
246 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000247 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
248 GrResourceCache::kNested_LockType));
249}
250
251GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
252 uint32_t v[4];
253 gen_stencil_key_values(sb, v);
254 GrResourceKey resourceKey(v);
255 return fTextureCache->createAndLock(resourceKey, sb);
256}
257
258GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
259 int sampleCnt) {
260 uint32_t v[4];
261 gen_stencil_key_values(width, height, sampleCnt, v);
262 GrResourceKey resourceKey(v);
263 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
264 GrResourceCache::kSingle_LockType);
265 if (NULL != entry) {
266 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
267 return sb;
268 } else {
269 return NULL;
270 }
271}
272
273void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
274 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000275}
276
277static void stretchImage(void* dst,
278 int dstW,
279 int dstH,
280 void* src,
281 int srcW,
282 int srcH,
283 int bpp) {
284 GrFixed dx = (srcW << 16) / dstW;
285 GrFixed dy = (srcH << 16) / dstH;
286
287 GrFixed y = dy >> 1;
288
289 int dstXLimit = dstW*bpp;
290 for (int j = 0; j < dstH; ++j) {
291 GrFixed x = dx >> 1;
292 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
293 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
294 for (int i = 0; i < dstXLimit; i += bpp) {
295 memcpy((uint8_t*) dstRow + i,
296 (uint8_t*) srcRow + (x>>16)*bpp,
297 bpp);
298 x += dx;
299 }
300 y += dy;
301 }
302}
303
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000304GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000305 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000306 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000307 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000308 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000309
310#if GR_DUMP_TEXTURE_UPLOAD
311 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
312#endif
313
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000314 TextureCacheEntry entry;
315 uint32_t v[4];
316 bool special = gen_texture_key_values(fGpu, sampler, key,
317 desc.fWidth, desc.fHeight, false, v);
318 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000319
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000320 if (special) {
321 TextureCacheEntry clampEntry =
322 findAndLockTexture(key, desc.fWidth, desc.fHeight,
323 GrSamplerState::ClampNoFilter());
324
325 if (NULL == clampEntry.texture()) {
326 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000327 GrSamplerState::ClampNoFilter(),
328 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000329 GrAssert(NULL != clampEntry.texture());
330 if (NULL == clampEntry.texture()) {
331 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000332 }
333 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000334 GrTextureDesc rtDesc = desc;
335 rtDesc.fFlags = rtDesc.fFlags |
336 kRenderTarget_GrTextureFlagBit |
337 kNoStencil_GrTextureFlagBit;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000338 rtDesc.fWidth =
339 GrNextPow2(GrMax<int>(desc.fWidth,
340 fGpu->getCaps().fMinRenderTargetWidth));
341 rtDesc.fHeight =
342 GrNextPow2(GrMax<int>(desc.fHeight,
343 fGpu->getCaps().fMinRenderTargetHeight));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000344
345 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
346
347 if (NULL != texture) {
348 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000349 reset_target_state(fGpu);
350
bsalomon@google.com27847de2011-02-22 20:59:41 +0000351 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000352 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000353
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000354 GrSamplerState::Filter filter;
355 // if filtering is not desired then we want to ensure all
356 // texels in the resampled image are copies of texels from
357 // the original.
358 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
359 filter = GrSamplerState::kNearest_Filter;
360 } else {
361 filter = GrSamplerState::kBilinear_Filter;
362 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000363 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
364 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000365 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000366 fGpu->setSamplerState(0, stretchSampler);
367
368 static const GrVertexLayout layout =
369 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
370 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
371
372 if (arg.succeeded()) {
373 GrPoint* verts = (GrPoint*) arg.vertices();
374 verts[0].setIRectFan(0, 0,
375 texture->width(),
376 texture->height(),
377 2*sizeof(GrPoint));
378 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
379 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
380 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000381 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000382 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000383 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000384 } else {
385 // TODO: Our CPU stretch doesn't filter. But we create separate
386 // stretched textures when the sampler state is either filtered or
387 // not. Either implement filtered stretch blit on CPU or just create
388 // one when FBO case fails.
389
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000390 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 // no longer need to clamp at min RT size.
392 rtDesc.fWidth = GrNextPow2(desc.fWidth);
393 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000394 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000395 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000396 rtDesc.fWidth *
397 rtDesc.fHeight);
398 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
399 srcData, desc.fWidth, desc.fHeight, bpp);
400
401 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
402
403 GrTexture* texture = fGpu->createTexture(rtDesc,
404 stretchedPixels.get(),
405 stretchedRowBytes);
406 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000407 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000408 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000409 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000410
411 } else {
412 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
413 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415 }
416 }
417 return entry;
418}
419
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000420namespace {
421inline void gen_scratch_tex_key_values(const GrGpu* gpu,
422 const GrTextureDesc& desc,
423 uint32_t v[4]) {
424 // Instead of a client-provided key of the texture contents
425 // we create a key of from the descriptor.
426 GrContext::TextureKey descKey = desc.fAALevel |
427 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000428 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000429 // this code path isn't friendly to tiling with NPOT restricitons
430 // We just pass ClampNoFilter()
431 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
432 desc.fWidth, desc.fHeight, true, v);
433}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000434}
435
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000436GrContext::TextureCacheEntry GrContext::lockScratchTexture(
437 const GrTextureDesc& inDesc,
438 ScratchTexMatch match) {
439
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000440 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441 if (kExact_ScratchTexMatch != match) {
442 // bin by pow2 with a reasonable min
443 static const int MIN_SIZE = 256;
444 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
445 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
446 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000447
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000448 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000449 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
450
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000451 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000452 int origWidth = desc.fWidth;
453 int origHeight = desc.fHeight;
454 bool doubledW = false;
455 bool doubledH = false;
456
457 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000458 uint32_t v[4];
459 gen_scratch_tex_key_values(fGpu, desc, v);
460 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000461 entry = fTextureCache->findAndLock(key,
462 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000463 // if we miss, relax the fit of the flags...
464 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000465 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000466 break;
467 }
468 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
469 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
470 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
471 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
472 } else if (!doubledW) {
473 desc.fFlags = inDesc.fFlags;
474 desc.fWidth *= 2;
475 doubledW = true;
476 } else if (!doubledH) {
477 desc.fFlags = inDesc.fFlags;
478 desc.fWidth = origWidth;
479 desc.fHeight *= 2;
480 doubledH = true;
481 } else {
482 break;
483 }
484
485 } while (true);
486
487 if (NULL == entry) {
488 desc.fFlags = inDesc.fFlags;
489 desc.fWidth = origWidth;
490 desc.fHeight = origHeight;
491 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
492 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000493 uint32_t v[4];
494 gen_scratch_tex_key_values(fGpu, desc, v);
495 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000496 entry = fTextureCache->createAndLock(key, texture);
497 }
498 }
499
500 // If the caller gives us the same desc/sampler twice we don't want
501 // to return the same texture the second time (unless it was previously
502 // released). So we detach the entry from the cache and reattach at release.
503 if (NULL != entry) {
504 fTextureCache->detach(entry);
505 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000506 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000507}
508
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000509void GrContext::unlockTexture(TextureCacheEntry entry) {
510 // If this is a scratch texture we detached it from the cache
511 // while it was locked (to avoid two callers simultaneously getting
512 // the same texture).
513 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
514 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000515 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000516 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000517 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000518}
519
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000520GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000521 void* srcData,
522 size_t rowBytes) {
523 return fGpu->createTexture(desc, srcData, rowBytes);
524}
525
526void GrContext::getTextureCacheLimits(int* maxTextures,
527 size_t* maxTextureBytes) const {
528 fTextureCache->getLimits(maxTextures, maxTextureBytes);
529}
530
531void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
532 fTextureCache->setLimits(maxTextures, maxTextureBytes);
533}
534
bsalomon@google.com91958362011-06-13 17:58:13 +0000535int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000536 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000537}
538
539int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000540 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000541}
542
543///////////////////////////////////////////////////////////////////////////////
544
bsalomon@google.come269f212011-11-07 13:29:52 +0000545GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
546 return fGpu->createPlatformTexture(desc);
547}
548
549GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
550 return fGpu->createPlatformRenderTarget(desc);
551}
552
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000553GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
554 // validate flags here so that GrGpu subclasses don't have to check
555 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
556 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000557 return NULL;
558 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000559 if (desc.fSampleCnt &&
560 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000561 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000562 }
563 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
564 desc.fSampleCnt &&
565 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
566 return NULL;
567 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000568 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000569}
570
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000571///////////////////////////////////////////////////////////////////////////////
572
bsalomon@google.com27847de2011-02-22 20:59:41 +0000573bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000574 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000575 const GrDrawTarget::Caps& caps = fGpu->getCaps();
576 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577 return false;
578 }
579
bsalomon@google.com27847de2011-02-22 20:59:41 +0000580 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
581
582 if (!isPow2) {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000583 if (!caps.fNPOTTextureSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000584 return false;
585 }
586
587 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
588 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000589 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000590 return false;
591 }
592 }
593 return true;
594}
595
596////////////////////////////////////////////////////////////////////////////////
597
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000598const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
599
bsalomon@google.com27847de2011-02-22 20:59:41 +0000600void GrContext::setClip(const GrClip& clip) {
601 fGpu->setClip(clip);
602 fGpu->enableState(GrDrawTarget::kClip_StateBit);
603}
604
605void GrContext::setClip(const GrIRect& rect) {
606 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000607 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000608 fGpu->setClip(clip);
609}
610
611////////////////////////////////////////////////////////////////////////////////
612
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000613void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000614 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000615 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000616}
617
618void GrContext::drawPaint(const GrPaint& paint) {
619 // set rect to be big enough to fill the space, but not super-huge, so we
620 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000621 GrRect r;
622 r.setLTRB(0, 0,
623 GrIntToScalar(getRenderTarget()->width()),
624 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000625 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000626 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000627 SkTLazy<GrPaint> tmpPaint;
628 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000629 // We attempt to map r by the inverse matrix and draw that. mapRect will
630 // map the four corners and bound them with a new rect. This will not
631 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000632 if (!this->getMatrix().hasPerspective()) {
633 if (!fGpu->getViewInverse(&inverse)) {
634 GrPrintf("Could not invert matrix");
635 return;
636 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000637 inverse.mapRect(&r);
638 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000639 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
640 if (!fGpu->getViewInverse(&inverse)) {
641 GrPrintf("Could not invert matrix");
642 return;
643 }
644 tmpPaint.set(paint);
645 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
646 p = tmpPaint.get();
647 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000648 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000649 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000650 // by definition this fills the entire clip, no need for AA
651 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000652 if (!tmpPaint.isValid()) {
653 tmpPaint.set(paint);
654 p = tmpPaint.get();
655 }
656 GrAssert(p == tmpPaint.get());
657 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000658 }
659 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000660}
661
bsalomon@google.com205d4602011-04-25 12:43:45 +0000662////////////////////////////////////////////////////////////////////////////////
663
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000664namespace {
665inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
666 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
667}
668}
669
bsalomon@google.com91958362011-06-13 17:58:13 +0000670struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000671 enum Downsample {
672 k4x4TwoPass_Downsample,
673 k4x4SinglePass_Downsample,
674 kFSAA_Downsample
675 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000676 int fTileSizeX;
677 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000678 int fTileCountX;
679 int fTileCountY;
680 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000681 GrAutoScratchTexture fOffscreen0;
682 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000683 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000684 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000685};
686
bsalomon@google.com471d4712011-08-23 15:45:25 +0000687bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000688 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000689#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000690 return false;
691#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000692 // Line primitves are always rasterized as 1 pixel wide.
693 // Super-sampling would make them too thin but MSAA would be OK.
694 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000695 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000696 return false;
697 }
698 if (target->getRenderTarget()->isMultisampled()) {
699 return false;
700 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000701 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000702#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000703 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000704#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000705 return false;
706 }
707 return true;
708#endif
709}
710
bsalomon@google.com91958362011-06-13 17:58:13 +0000711bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000712 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000713 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000714 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000715 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000716
717 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000718
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000719 GrAssert(NULL == record->fOffscreen0.texture());
720 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000721 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000722
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000723 int boundW = boundRect.width();
724 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000725
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000726 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000727
728 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
729 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
730
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000731 if (requireStencil) {
732 desc.fFlags = kRenderTarget_GrTextureFlagBit;
733 } else {
734 desc.fFlags = kRenderTarget_GrTextureFlagBit |
735 kNoStencil_GrTextureFlagBit;
736 }
737
bsalomon@google.comc4364992011-11-07 15:54:49 +0000738 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000739
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000740 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000741 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000742 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000743 desc.fAALevel = kMed_GrAALevel;
744 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000745 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000746 OffscreenRecord::k4x4SinglePass_Downsample :
747 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000748 record->fScale = OFFSCREEN_SSAA_SCALE;
749 // both downsample paths assume this
750 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000751 desc.fAALevel = kNone_GrAALevel;
752 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000753
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000754 desc.fWidth *= record->fScale;
755 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000756 record->fOffscreen0.set(this, desc);
757 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000758 return false;
759 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000760 // the approximate lookup might have given us some slop space, might as well
761 // use it when computing the tiles size.
762 // these are scale values, will adjust after considering
763 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000764 record->fTileSizeX = record->fOffscreen0.texture()->width();
765 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000766
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000767 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768 desc.fWidth /= 2;
769 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000770 record->fOffscreen1.set(this, desc);
771 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000772 return false;
773 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000774 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000775 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000776 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000777 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000778 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000779 record->fTileSizeX /= record->fScale;
780 record->fTileSizeY /= record->fScale;
781
782 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
783 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
784
tomhudson@google.com237a4612011-07-19 15:44:00 +0000785 record->fClip = target->getClip();
786
bsalomon@google.com91958362011-06-13 17:58:13 +0000787 target->saveCurrentDrawState(&record->fSavedState);
788 return true;
789}
790
791void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
792 const GrIRect& boundRect,
793 int tileX, int tileY,
794 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000796 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000797 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000798
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000799 GrPaint tempPaint;
800 tempPaint.reset();
801 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000802 target->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000803#if PREFER_MSAA_OFFSCREEN_AA
804 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
805#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000806
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000807 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000808 int left = boundRect.fLeft + tileX * record->fTileSizeX;
809 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000810 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000811 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000812 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000813 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000814 target->postConcatViewMatrix(scaleM);
815
bsalomon@google.com91958362011-06-13 17:58:13 +0000816 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000817 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000818 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000819 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000820 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
821 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000822 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000823#if 0
824 // visualize tile boundaries by setting edges of offscreen to white
825 // and interior to tranparent. black.
826 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000827
bsalomon@google.com91958362011-06-13 17:58:13 +0000828 static const int gOffset = 2;
829 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
830 record->fScale * w - gOffset,
831 record->fScale * h - gOffset);
832 target->clear(&clear2, 0x0);
833#else
834 target->clear(&clear, 0x0);
835#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000836}
837
bsalomon@google.com91958362011-06-13 17:58:13 +0000838void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000839 const GrPaint& paint,
840 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000841 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000842 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000843 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000844 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000845 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000846 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000847 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
848 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000849 tileRect.fRight = (tileX == record->fTileCountX-1) ?
850 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000851 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000852 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
853 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000854 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000855
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000856 GrSamplerState::Filter filter;
857 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
858 filter = GrSamplerState::k4x4Downsample_Filter;
859 } else {
860 filter = GrSamplerState::kBilinear_Filter;
861 }
862
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000863 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000864 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000865 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000866
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000867 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000868 int scale;
869
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000870 enum {
871 kOffscreenStage = GrPaint::kTotalStages,
872 };
873
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000874 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000875 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000876 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000877 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000878
879 // Do 2x2 downsample from first to second
880 target->setTexture(kOffscreenStage, src);
881 target->setRenderTarget(dst);
882 target->setViewMatrix(GrMatrix::I());
883 sampleM.setScale(scale * GR_Scalar1 / src->width(),
884 scale * GR_Scalar1 / src->height());
885 sampler.setMatrix(sampleM);
886 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000887 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
888 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000889 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
890
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000891 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000892 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000893 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000894 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000895 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000896 } else {
897 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
898 record->fDownsample);
899 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000900 }
901
bsalomon@google.com91958362011-06-13 17:58:13 +0000902 // setup for draw back to main RT, we use the original
903 // draw state setup by the caller plus an additional coverage
904 // stage to handle the AA resolve. Also, we use an identity
905 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000906 int stageMask = paint.getActiveStageMask();
907
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000908 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000909 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000910
911 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000912 GrMatrix invVM;
913 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000914 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000915 }
916 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000917 // This is important when tiling, otherwise second tile's
918 // pass 1 view matrix will be incorrect.
919 GrDrawTarget::AutoViewMatrixRestore avmr(target);
920
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000921 target->setViewMatrix(GrMatrix::I());
922
923 target->setTexture(kOffscreenStage, src);
924 sampleM.setScale(scale * GR_Scalar1 / src->width(),
925 scale * GR_Scalar1 / src->height());
926 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000927 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
928 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000929 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000930 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000931
reed@google.com20efde72011-05-09 17:00:02 +0000932 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000933 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000934 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000935 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000936}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000937
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000938void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
939 GrPathRenderer* pr,
940 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000941 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000942}
943
944////////////////////////////////////////////////////////////////////////////////
945
bsalomon@google.com27847de2011-02-22 20:59:41 +0000946/* create a triangle strip that strokes the specified triangle. There are 8
947 unique vertices, but we repreat the last 2 to close up. Alternatively we
948 could use an indices array, and then only send 8 verts, but not sure that
949 would be faster.
950 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000951static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000952 GrScalar width) {
953 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000954 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000955
956 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
957 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
958 verts[2].set(rect.fRight - rad, rect.fTop + rad);
959 verts[3].set(rect.fRight + rad, rect.fTop - rad);
960 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
961 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
962 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
963 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
964 verts[8] = verts[0];
965 verts[9] = verts[1];
966}
967
bsalomon@google.com205d4602011-04-25 12:43:45 +0000968static void setInsetFan(GrPoint* pts, size_t stride,
969 const GrRect& r, GrScalar dx, GrScalar dy) {
970 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
971}
972
973static const uint16_t gFillAARectIdx[] = {
974 0, 1, 5, 5, 4, 0,
975 1, 2, 6, 6, 5, 1,
976 2, 3, 7, 7, 6, 2,
977 3, 0, 4, 4, 7, 3,
978 4, 5, 6, 6, 7, 4,
979};
980
981int GrContext::aaFillRectIndexCount() const {
982 return GR_ARRAY_COUNT(gFillAARectIdx);
983}
984
985GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
986 if (NULL == fAAFillRectIndexBuffer) {
987 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
988 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000989 if (NULL != fAAFillRectIndexBuffer) {
990 #if GR_DEBUG
991 bool updated =
992 #endif
993 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
994 sizeof(gFillAARectIdx));
995 GR_DEBUGASSERT(updated);
996 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000997 }
998 return fAAFillRectIndexBuffer;
999}
1000
1001static const uint16_t gStrokeAARectIdx[] = {
1002 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
1003 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1004 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1005 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1006
1007 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1008 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1009 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1010 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1011
1012 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1013 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1014 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1015 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1016};
1017
1018int GrContext::aaStrokeRectIndexCount() const {
1019 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1020}
1021
1022GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1023 if (NULL == fAAStrokeRectIndexBuffer) {
1024 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1025 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001026 if (NULL != fAAStrokeRectIndexBuffer) {
1027 #if GR_DEBUG
1028 bool updated =
1029 #endif
1030 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1031 sizeof(gStrokeAARectIdx));
1032 GR_DEBUGASSERT(updated);
1033 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001034 }
1035 return fAAStrokeRectIndexBuffer;
1036}
1037
bsalomon@google.coma3108262011-10-10 14:08:47 +00001038static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1039 bool useCoverage) {
1040 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001041 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001042 if (NULL != target->getTexture(s)) {
1043 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1044 }
1045 }
1046 if (useCoverage) {
1047 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1048 } else {
1049 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1050 }
1051 return layout;
1052}
1053
bsalomon@google.com205d4602011-04-25 12:43:45 +00001054void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001055 const GrRect& devRect,
1056 bool useVertexCoverage) {
1057 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001058
1059 size_t vsize = GrDrawTarget::VertexSize(layout);
1060
1061 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001062 if (!geo.succeeded()) {
1063 GrPrintf("Failed to get space for vertices!\n");
1064 return;
1065 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001066 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1067 if (NULL == indexBuffer) {
1068 GrPrintf("Failed to create index buffer!\n");
1069 return;
1070 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001071
1072 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1073
1074 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1075 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1076
1077 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1078 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1079
1080 verts += sizeof(GrPoint);
1081 for (int i = 0; i < 4; ++i) {
1082 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1083 }
1084
bsalomon@google.coma3108262011-10-10 14:08:47 +00001085 GrColor innerColor;
1086 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001087 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001088 } else {
1089 innerColor = target->getColor();
1090 }
1091
bsalomon@google.com205d4602011-04-25 12:43:45 +00001092 verts += 4 * vsize;
1093 for (int i = 0; i < 4; ++i) {
1094 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1095 }
1096
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001097 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001098
1099 target->drawIndexed(kTriangles_PrimitiveType, 0,
1100 0, 8, this->aaFillRectIndexCount());
1101}
1102
bsalomon@google.coma3108262011-10-10 14:08:47 +00001103void GrContext::strokeAARect(GrDrawTarget* target,
1104 const GrRect& devRect,
1105 const GrVec& devStrokeSize,
1106 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001107 const GrScalar& dx = devStrokeSize.fX;
1108 const GrScalar& dy = devStrokeSize.fY;
1109 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1110 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1111
bsalomon@google.com205d4602011-04-25 12:43:45 +00001112 GrScalar spare;
1113 {
1114 GrScalar w = devRect.width() - dx;
1115 GrScalar h = devRect.height() - dy;
1116 spare = GrMin(w, h);
1117 }
1118
1119 if (spare <= 0) {
1120 GrRect r(devRect);
1121 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001122 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001123 return;
1124 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001125 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001126 size_t vsize = GrDrawTarget::VertexSize(layout);
1127
1128 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001129 if (!geo.succeeded()) {
1130 GrPrintf("Failed to get space for vertices!\n");
1131 return;
1132 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001133 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1134 if (NULL == indexBuffer) {
1135 GrPrintf("Failed to create index buffer!\n");
1136 return;
1137 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001138
1139 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1140
1141 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1142 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1143 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1144 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1145
1146 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1147 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1148 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1149 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1150
1151 verts += sizeof(GrPoint);
1152 for (int i = 0; i < 4; ++i) {
1153 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1154 }
1155
bsalomon@google.coma3108262011-10-10 14:08:47 +00001156 GrColor innerColor;
1157 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001158 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001159 } else {
1160 innerColor = target->getColor();
1161 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001162 verts += 4 * vsize;
1163 for (int i = 0; i < 8; ++i) {
1164 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1165 }
1166
1167 verts += 8 * vsize;
1168 for (int i = 0; i < 8; ++i) {
1169 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1170 }
1171
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001172 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001173 target->drawIndexed(kTriangles_PrimitiveType,
1174 0, 0, 16, aaStrokeRectIndexCount());
1175}
1176
reed@google.com20efde72011-05-09 17:00:02 +00001177/**
1178 * Returns true if the rects edges are integer-aligned.
1179 */
1180static bool isIRect(const GrRect& r) {
1181 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1182 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1183}
1184
bsalomon@google.com205d4602011-04-25 12:43:45 +00001185static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001186 const GrRect& rect,
1187 GrScalar width,
1188 const GrMatrix* matrix,
1189 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001190 GrRect* devRect,
1191 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001192 // we use a simple alpha ramp to do aa on axis-aligned rects
1193 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001194 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001195
bsalomon@google.coma3108262011-10-10 14:08:47 +00001196 // we are keeping around the "tweak the alpha" trick because
1197 // it is our only hope for the fixed-pipe implementation.
1198 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001199 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001200 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001201 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001202 if (target->getCaps().fSupportPerVertexCoverage) {
1203 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001204#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001205 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001206#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001207 return false;
1208 } else {
1209 *useVertexCoverage = true;
1210 }
1211 } else {
1212 GrPrintf("Rect AA dropped because no support for coverage.\n");
1213 return false;
1214 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001215 }
1216
1217 if (target->getRenderTarget()->isMultisampled()) {
1218 return false;
1219 }
1220
bsalomon@google.com471d4712011-08-23 15:45:25 +00001221 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001222 return false;
1223 }
1224
1225 if (!target->getViewMatrix().preservesAxisAlignment()) {
1226 return false;
1227 }
1228
1229 if (NULL != matrix &&
1230 !matrix->preservesAxisAlignment()) {
1231 return false;
1232 }
1233
1234 *combinedMatrix = target->getViewMatrix();
1235 if (NULL != matrix) {
1236 combinedMatrix->preConcat(*matrix);
1237 GrAssert(combinedMatrix->preservesAxisAlignment());
1238 }
1239
1240 combinedMatrix->mapRect(devRect, rect);
1241 devRect->sort();
1242
1243 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001244 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001245 } else {
1246 return true;
1247 }
1248}
1249
bsalomon@google.com27847de2011-02-22 20:59:41 +00001250void GrContext::drawRect(const GrPaint& paint,
1251 const GrRect& rect,
1252 GrScalar width,
1253 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001254 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255
1256 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001257 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258
bsalomon@google.com205d4602011-04-25 12:43:45 +00001259 GrRect devRect = rect;
1260 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001261 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001262 bool needAA = paint.fAntiAlias &&
1263 !this->getRenderTarget()->isMultisampled();
1264 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1265 &combinedMatrix, &devRect,
1266 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001267
1268 if (doAA) {
1269 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001270 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001271 GrMatrix inv;
1272 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001273 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001274 }
1275 }
1276 target->setViewMatrix(GrMatrix::I());
1277 if (width >= 0) {
1278 GrVec strokeSize;;
1279 if (width > 0) {
1280 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001281 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001282 strokeSize.setAbs(strokeSize);
1283 } else {
1284 strokeSize.set(GR_Scalar1, GR_Scalar1);
1285 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001286 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001287 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001288 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001289 }
1290 return;
1291 }
1292
bsalomon@google.com27847de2011-02-22 20:59:41 +00001293 if (width >= 0) {
1294 // TODO: consider making static vertex buffers for these cases.
1295 // Hairline could be done by just adding closing vertex to
1296 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001297 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1298
bsalomon@google.com27847de2011-02-22 20:59:41 +00001299 static const int worstCaseVertCount = 10;
1300 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1301
1302 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001303 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001304 return;
1305 }
1306
1307 GrPrimitiveType primType;
1308 int vertCount;
1309 GrPoint* vertex = geo.positions();
1310
1311 if (width > 0) {
1312 vertCount = 10;
1313 primType = kTriangleStrip_PrimitiveType;
1314 setStrokeRectStrip(vertex, rect, width);
1315 } else {
1316 // hairline
1317 vertCount = 5;
1318 primType = kLineStrip_PrimitiveType;
1319 vertex[0].set(rect.fLeft, rect.fTop);
1320 vertex[1].set(rect.fRight, rect.fTop);
1321 vertex[2].set(rect.fRight, rect.fBottom);
1322 vertex[3].set(rect.fLeft, rect.fBottom);
1323 vertex[4].set(rect.fLeft, rect.fTop);
1324 }
1325
1326 GrDrawTarget::AutoViewMatrixRestore avmr;
1327 if (NULL != matrix) {
1328 avmr.set(target);
1329 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001330 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 }
1332
1333 target->drawNonIndexed(primType, 0, vertCount);
1334 } else {
1335 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001336 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001337 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1338 if (NULL == sqVB) {
1339 GrPrintf("Failed to create static rect vb.\n");
1340 return;
1341 }
1342 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001343 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1344 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001345 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001346 0, rect.height(), rect.fTop,
1347 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001348
1349 if (NULL != matrix) {
1350 m.postConcat(*matrix);
1351 }
1352
1353 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001354 target->preConcatSamplerMatrices(stageMask, m);
1355
bsalomon@google.com27847de2011-02-22 20:59:41 +00001356 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1357 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001358 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001359 #endif
1360 }
1361}
1362
1363void GrContext::drawRectToRect(const GrPaint& paint,
1364 const GrRect& dstRect,
1365 const GrRect& srcRect,
1366 const GrMatrix* dstMatrix,
1367 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001368 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001369
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001370 // srcRect refers to paint's first texture
1371 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372 drawRect(paint, dstRect, -1, dstMatrix);
1373 return;
1374 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001375
bsalomon@google.com27847de2011-02-22 20:59:41 +00001376 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1377
1378#if GR_STATIC_RECT_VB
1379 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001380
1381 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001382 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1383
1384 GrMatrix m;
1385
1386 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1387 0, dstRect.height(), dstRect.fTop,
1388 0, 0, GrMatrix::I()[8]);
1389 if (NULL != dstMatrix) {
1390 m.postConcat(*dstMatrix);
1391 }
1392 target->preConcatViewMatrix(m);
1393
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001394 // srcRect refers to first stage
1395 int otherStageMask = paint.getActiveStageMask() &
1396 (~(1 << GrPaint::kFirstTextureStage));
1397 if (otherStageMask) {
1398 target->preConcatSamplerMatrices(otherStageMask, m);
1399 }
1400
bsalomon@google.com27847de2011-02-22 20:59:41 +00001401 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1402 0, srcRect.height(), srcRect.fTop,
1403 0, 0, GrMatrix::I()[8]);
1404 if (NULL != srcMatrix) {
1405 m.postConcat(*srcMatrix);
1406 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001407 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001408
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001409 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1410 if (NULL == sqVB) {
1411 GrPrintf("Failed to create static rect vb.\n");
1412 return;
1413 }
1414 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1416#else
1417
1418 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001419#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001421#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001422 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1423#endif
1424
tomhudson@google.com93813632011-10-27 20:21:16 +00001425 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1426 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001427 srcRects[0] = &srcRect;
1428 srcMatrices[0] = srcMatrix;
1429
1430 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1431#endif
1432}
1433
1434void GrContext::drawVertices(const GrPaint& paint,
1435 GrPrimitiveType primitiveType,
1436 int vertexCount,
1437 const GrPoint positions[],
1438 const GrPoint texCoords[],
1439 const GrColor colors[],
1440 const uint16_t indices[],
1441 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001442 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001443
1444 GrDrawTarget::AutoReleaseGeometry geo;
1445
1446 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1447
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001448 bool hasTexCoords[GrPaint::kTotalStages] = {
1449 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1450 0 // remaining stages use positions
1451 };
1452
1453 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001454
1455 if (NULL != colors) {
1456 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001457 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001458 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001459
1460 if (sizeof(GrPoint) != vertexSize) {
1461 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001462 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463 return;
1464 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001465 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001467 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1468 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001469 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001470 NULL,
1471 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472 void* curVertex = geo.vertices();
1473
1474 for (int i = 0; i < vertexCount; ++i) {
1475 *((GrPoint*)curVertex) = positions[i];
1476
1477 if (texOffsets[0] > 0) {
1478 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1479 }
1480 if (colorOffset > 0) {
1481 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1482 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001483 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001484 }
1485 } else {
1486 target->setVertexSourceToArray(layout, positions, vertexCount);
1487 }
1488
bsalomon@google.com91958362011-06-13 17:58:13 +00001489 // we don't currently apply offscreen AA to this path. Need improved
1490 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001491
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001492 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001493 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001494 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001495 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001496 target->drawNonIndexed(primitiveType, 0, vertexCount);
1497 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498}
1499
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001500///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001501
reed@google.com07f3ee12011-05-16 17:21:57 +00001502void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1503 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001504
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001505 if (path.isEmpty()) {
1506#if GR_DEBUG
1507 GrPrintf("Empty path should have been caught by canvas.\n");
1508#endif
1509 if (GrIsFillInverted(fill)) {
1510 this->drawPaint(paint);
1511 }
1512 return;
1513 }
1514
bsalomon@google.com27847de2011-02-22 20:59:41 +00001515 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001516
bsalomon@google.com289533a2011-10-27 12:34:25 +00001517 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1518
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001519 // An Assumption here is that path renderer would use some form of tweaking
1520 // the src color (either the input alpha or in the frag shader) to implement
1521 // aa. If we have some future driver-mojo path AA that can do the right
1522 // thing WRT to the blend then we'll need some query on the PR.
1523 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001524#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001525 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001526#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001527 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001528 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001529
1530 bool doOSAA = false;
1531 GrPathRenderer* pr = NULL;
1532 if (prAA) {
1533 pr = this->getPathRenderer(path, fill, true);
1534 if (NULL == pr) {
1535 prAA = false;
1536 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1537 pr = this->getPathRenderer(path, fill, false);
1538 }
1539 } else {
1540 pr = this->getPathRenderer(path, fill, false);
1541 }
1542
bsalomon@google.com30085192011-08-19 15:42:31 +00001543 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001544#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001545 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001546#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001547 return;
1548 }
1549
bsalomon@google.com289533a2011-10-27 12:34:25 +00001550 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.comee435122011-07-01 14:57:55 +00001551 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001552
bsalomon@google.com289533a2011-10-27 12:34:25 +00001553 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001554 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001555
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001556 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001557 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1558 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001559 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001560 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001561 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001562 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001563 return;
1564 }
1565 }
reed@google.com70c136e2011-06-03 19:51:26 +00001566
reed@google.com07f3ee12011-05-16 17:21:57 +00001567 GrRect pathBounds = path.getBounds();
1568 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001569 if (NULL != translate) {
1570 pathBounds.offset(*translate);
1571 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001572 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001573 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001574 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001575 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001576 return;
1577 }
1578 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001579 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001580 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1581 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001582 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1583 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1584 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001585 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001586 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1587 }
1588 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001589 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001590 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001591 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1592 GrRect rect;
1593 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001594 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1595 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001596 target->drawSimpleRect(rect, NULL, stageMask);
1597 }
1598 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001599 rect.iset(clipIBounds.fLeft, bound.fTop,
1600 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001601 target->drawSimpleRect(rect, NULL, stageMask);
1602 }
1603 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001604 rect.iset(bound.fRight, bound.fTop,
1605 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001606 target->drawSimpleRect(rect, NULL, stageMask);
1607 }
1608 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001609 rect.iset(clipIBounds.fLeft, bound.fBottom,
1610 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001611 target->drawSimpleRect(rect, NULL, stageMask);
1612 }
1613 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001614 return;
1615 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001616 }
1617 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001618}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001619
bsalomon@google.com27847de2011-02-22 20:59:41 +00001620////////////////////////////////////////////////////////////////////////////////
1621
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001622bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001623 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001624}
1625
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001626void GrContext::flush(int flagsBitfield) {
1627 if (kDiscard_FlushBit & flagsBitfield) {
1628 fDrawBuffer->reset();
1629 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001630 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001631 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001632 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001633 fGpu->forceRenderTargetFlush();
1634 }
1635}
1636
1637void GrContext::flushText() {
1638 if (kText_DrawCategory == fLastDrawCategory) {
1639 flushDrawBuffer();
1640 }
1641}
1642
1643void GrContext::flushDrawBuffer() {
1644#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001645 if (fDrawBuffer) {
1646 fDrawBuffer->playback(fGpu);
1647 fDrawBuffer->reset();
1648 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001649#endif
1650}
1651
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001652bool GrContext::readTexturePixels(GrTexture* texture,
1653 int left, int top, int width, int height,
1654 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001655 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001656
1657 // TODO: code read pixels for textures that aren't rendertargets
1658
1659 this->flush();
1660 GrRenderTarget* target = texture->asRenderTarget();
1661 if (NULL != target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001662 return this->readRenderTargetPixels(target,
1663 left, top, width, height,
1664 config, buffer, 0);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001665 } else {
1666 return false;
1667 }
1668}
1669
1670bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
bsalomon@google.comc6980972011-11-02 19:57:21 +00001671 int left, int top, int width, int height,
1672 GrPixelConfig config, void* buffer,
1673 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001674 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001675 if (NULL == target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001676 target = fGpu->getRenderTarget();
1677 if (NULL == target) {
1678 return false;
1679 }
1680 }
1681
1682 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1683 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1684 // not supported at this time.
1685 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1686 !GrPixelConfigIsUnpremultiplied(config)) {
1687 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001688 }
1689
bsalomon@google.comc4364992011-11-07 15:54:49 +00001690 this->flush();
1691
1692 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001693 bool swapRAndB = NULL != src &&
1694 fGpu->preferredReadPixelsConfig(config) ==
1695 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001696
1697 bool flipY = NULL != src &&
1698 fGpu->readPixelsWillPayForYFlip(target, left, top,
1699 width, height, config,
1700 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001701 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1702 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001703
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001704 if (NULL == src && alphaConversion) {
1705 // we should fallback to cpu conversion here. This could happen when
1706 // we were given an external render target by the client that is not
1707 // also a texture (e.g. FBO 0 in GL)
1708 return false;
1709 }
1710
1711 // we draw to a scratch texture if any of these conversion are applied
1712 if (flipY || swapRAndB || alphaConversion) {
1713 GrAssert(NULL != src);
1714 if (swapRAndB) {
1715 config = GrPixelConfigSwapRAndB(config);
1716 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001717 }
1718 // Make the scratch a render target because we don't have a robust
1719 // readTexturePixels as of yet (it calls this function).
1720 const GrTextureDesc desc = {
1721 kRenderTarget_GrTextureFlagBit,
1722 kNone_GrAALevel,
1723 width, height,
1724 config
1725 };
1726 GrAutoScratchTexture ast(this, desc);
1727 GrTexture* texture = ast.texture();
1728 if (!texture) {
1729 return false;
1730 }
1731 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001732 GrAssert(NULL != target);
1733
1734 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001735 reset_target_state(fGpu);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001736
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001737 fGpu->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001738
1739 GrSamplerState sampler;
1740 sampler.setClampNoFilter();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001741 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001742 GrMatrix matrix;
1743 if (flipY) {
1744 matrix.setTranslate(SK_Scalar1 * left,
1745 SK_Scalar1 * (top + height));
1746 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1747 } else {
1748 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1749 }
1750 matrix.postIDiv(src->width(), src->height());
1751 sampler.setMatrix(matrix);
1752 fGpu->setSamplerState(0, sampler);
1753 fGpu->setTexture(0, src);
1754 GrRect rect;
1755 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1756 fGpu->drawSimpleRect(rect, NULL, 0x1);
1757 left = 0;
1758 top = 0;
1759 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001760 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001761 left, top, width, height,
1762 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001763}
1764
1765void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001766 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001767 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001768 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001769
1770 // TODO: when underlying api has a direct way to do this we should use it
1771 // (e.g. glDrawPixels on desktop GL).
1772
bsalomon@google.comc4364992011-11-07 15:54:49 +00001773 this->flush(kForceCurrentRenderTarget_FlushBit);
bsalomon@google.com5c638652011-07-18 19:31:59 +00001774
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001775 const GrTextureDesc desc = {
1776 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001777 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001778 GrAutoScratchTexture ast(this, desc);
1779 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001780 if (NULL == texture) {
1781 return;
1782 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001783 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001784
bsalomon@google.com27847de2011-02-22 20:59:41 +00001785 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001786 reset_target_state(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001787
1788 GrMatrix matrix;
1789 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1790 fGpu->setViewMatrix(matrix);
1791
bsalomon@google.com27847de2011-02-22 20:59:41 +00001792 fGpu->setTexture(0, texture);
1793
1794 GrSamplerState sampler;
1795 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001796 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001797 sampler.setMatrix(matrix);
1798 fGpu->setSamplerState(0, sampler);
1799
1800 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1801 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001802 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001803 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1804 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001805 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001806 return;
1807 }
1808 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1809 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1810}
1811////////////////////////////////////////////////////////////////////////////////
1812
1813void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001814
1815 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1816 int s = i + GrPaint::kFirstTextureStage;
1817 target->setTexture(s, paint.getTexture(i));
1818 target->setSamplerState(s, *paint.getTextureSampler(i));
1819 }
1820
1821 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1822
1823 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1824 int s = i + GrPaint::kFirstMaskStage;
1825 target->setTexture(s, paint.getMask(i));
1826 target->setSamplerState(s, *paint.getMaskSampler(i));
1827 }
1828
bsalomon@google.com27847de2011-02-22 20:59:41 +00001829 target->setColor(paint.fColor);
1830
1831 if (paint.fDither) {
1832 target->enableState(GrDrawTarget::kDither_StateBit);
1833 } else {
1834 target->disableState(GrDrawTarget::kDither_StateBit);
1835 }
1836 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001837 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001838 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001839 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001840 }
1841 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001842 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001843
1844 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1845 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1846 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001847}
1848
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001849GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001850 DrawCategory category) {
1851 if (category != fLastDrawCategory) {
1852 flushDrawBuffer();
1853 fLastDrawCategory = category;
1854 }
1855 SetPaint(paint, fGpu);
1856 GrDrawTarget* target = fGpu;
1857 switch (category) {
1858 case kText_DrawCategory:
1859#if DEFER_TEXT_RENDERING
1860 target = fDrawBuffer;
1861 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1862#else
1863 target = fGpu;
1864#endif
1865 break;
1866 case kUnbuffered_DrawCategory:
1867 target = fGpu;
1868 break;
1869 case kBuffered_DrawCategory:
1870 target = fDrawBuffer;
1871 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1872 break;
1873 }
1874 return target;
1875}
1876
bsalomon@google.com289533a2011-10-27 12:34:25 +00001877GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1878 GrPathFill fill,
1879 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001880 if (NULL == fPathRendererChain) {
1881 fPathRendererChain =
1882 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1883 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001884 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1885 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001886}
1887
bsalomon@google.com27847de2011-02-22 20:59:41 +00001888////////////////////////////////////////////////////////////////////////////////
1889
bsalomon@google.com27847de2011-02-22 20:59:41 +00001890void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001891 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001892 fGpu->setRenderTarget(target);
1893}
1894
1895GrRenderTarget* GrContext::getRenderTarget() {
1896 return fGpu->getRenderTarget();
1897}
1898
1899const GrRenderTarget* GrContext::getRenderTarget() const {
1900 return fGpu->getRenderTarget();
1901}
1902
1903const GrMatrix& GrContext::getMatrix() const {
1904 return fGpu->getViewMatrix();
1905}
1906
1907void GrContext::setMatrix(const GrMatrix& m) {
1908 fGpu->setViewMatrix(m);
1909}
1910
1911void GrContext::concatMatrix(const GrMatrix& m) const {
1912 fGpu->preConcatViewMatrix(m);
1913}
1914
1915static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1916 intptr_t mask = 1 << shift;
1917 if (pred) {
1918 bits |= mask;
1919 } else {
1920 bits &= ~mask;
1921 }
1922 return bits;
1923}
1924
1925void GrContext::resetStats() {
1926 fGpu->resetStats();
1927}
1928
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001929const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001930 return fGpu->getStats();
1931}
1932
1933void GrContext::printStats() const {
1934 fGpu->printStats();
1935}
1936
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001937GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938 fGpu = gpu;
1939 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001940 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001941
bsalomon@google.com30085192011-08-19 15:42:31 +00001942 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001943
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001944 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1945 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946 fFontCache = new GrFontCache(fGpu);
1947
1948 fLastDrawCategory = kUnbuffered_DrawCategory;
1949
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001950 fDrawBuffer = NULL;
1951 fDrawBufferVBAllocPool = NULL;
1952 fDrawBufferIBAllocPool = NULL;
1953
bsalomon@google.com205d4602011-04-25 12:43:45 +00001954 fAAFillRectIndexBuffer = NULL;
1955 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001956
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001957 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1958 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001959 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1960 }
1961 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001962
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001963 this->setupDrawBuffer();
1964}
1965
1966void GrContext::setupDrawBuffer() {
1967
1968 GrAssert(NULL == fDrawBuffer);
1969 GrAssert(NULL == fDrawBufferVBAllocPool);
1970 GrAssert(NULL == fDrawBufferIBAllocPool);
1971
bsalomon@google.com27847de2011-02-22 20:59:41 +00001972#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001973 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001974 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001975 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1976 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001977 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001978 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001979 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001980 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1981
bsalomon@google.com471d4712011-08-23 15:45:25 +00001982 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1983 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001984 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001985#endif
1986
1987#if BATCH_RECT_TO_RECT
1988 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1989#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001990}
1991
bsalomon@google.com27847de2011-02-22 20:59:41 +00001992GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1993 GrDrawTarget* target;
1994#if DEFER_TEXT_RENDERING
1995 target = prepareToDraw(paint, kText_DrawCategory);
1996#else
1997 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1998#endif
1999 SetPaint(paint, target);
2000 return target;
2001}
2002
2003const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2004 return fGpu->getQuadIndexBuffer();
2005}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002006
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002007void GrContext::convolveInX(GrTexture* texture,
2008 const SkRect& rect,
2009 const float* kernel,
2010 int kernelWidth) {
2011 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
2012 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2013}
2014
2015void GrContext::convolveInY(GrTexture* texture,
2016 const SkRect& rect,
2017 const float* kernel,
2018 int kernelWidth) {
2019 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
2020 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2021}
2022
2023void GrContext::convolve(GrTexture* texture,
2024 const SkRect& rect,
2025 float imageIncrement[2],
2026 const float* kernel,
2027 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002028 GrDrawTarget::AutoStateRestore asr(fGpu);
2029 GrMatrix sampleM;
2030 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
2031 GrSamplerState::kClamp_WrapMode,
2032 GrSamplerState::kConvolution_Filter);
2033 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002034 sampleM.setScale(GR_Scalar1 / texture->width(),
2035 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002036 sampler.setMatrix(sampleM);
2037 fGpu->setSamplerState(0, sampler);
2038 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002039 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002040 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002041 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2042}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002043
2044///////////////////////////////////////////////////////////////////////////////