blob: 12b8b07a0e7edffad686789b7cb5bdc31cde8181 [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 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001710 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001711 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001712 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,
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001724 { config }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001725 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001726
1727 ast.set(this, desc);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001728 GrTexture* texture = ast.texture();
1729 if (!texture) {
1730 return false;
1731 }
1732 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001733 GrAssert(NULL != target);
1734
1735 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001736 reset_target_state(fGpu);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001737
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001738 fGpu->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001739
1740 GrSamplerState sampler;
1741 sampler.setClampNoFilter();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001742 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001743 GrMatrix matrix;
1744 if (flipY) {
1745 matrix.setTranslate(SK_Scalar1 * left,
1746 SK_Scalar1 * (top + height));
1747 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1748 } else {
1749 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1750 }
1751 matrix.postIDiv(src->width(), src->height());
1752 sampler.setMatrix(matrix);
1753 fGpu->setSamplerState(0, sampler);
1754 fGpu->setTexture(0, src);
1755 GrRect rect;
1756 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1757 fGpu->drawSimpleRect(rect, NULL, 0x1);
1758 left = 0;
1759 top = 0;
1760 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001761 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001762 left, top, width, height,
1763 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001764}
1765
1766void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001767 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001768 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001769 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001770
1771 // TODO: when underlying api has a direct way to do this we should use it
1772 // (e.g. glDrawPixels on desktop GL).
1773
bsalomon@google.comc4364992011-11-07 15:54:49 +00001774 this->flush(kForceCurrentRenderTarget_FlushBit);
bsalomon@google.com5c638652011-07-18 19:31:59 +00001775
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001776 const GrTextureDesc desc = {
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001777 kNone_GrTextureFlags, kNone_GrAALevel, width, height, { config }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001778 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001779 GrAutoScratchTexture ast(this, desc);
1780 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001781 if (NULL == texture) {
1782 return;
1783 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001784 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001785
bsalomon@google.com27847de2011-02-22 20:59:41 +00001786 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001787 reset_target_state(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001788
1789 GrMatrix matrix;
1790 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1791 fGpu->setViewMatrix(matrix);
1792
bsalomon@google.com27847de2011-02-22 20:59:41 +00001793 fGpu->setTexture(0, texture);
1794
1795 GrSamplerState sampler;
1796 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001797 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001798 sampler.setMatrix(matrix);
1799 fGpu->setSamplerState(0, sampler);
1800
1801 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1802 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001803 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001804 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1805 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001806 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001807 return;
1808 }
1809 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1810 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1811}
1812////////////////////////////////////////////////////////////////////////////////
1813
1814void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001815
1816 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1817 int s = i + GrPaint::kFirstTextureStage;
1818 target->setTexture(s, paint.getTexture(i));
1819 target->setSamplerState(s, *paint.getTextureSampler(i));
1820 }
1821
1822 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1823
1824 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1825 int s = i + GrPaint::kFirstMaskStage;
1826 target->setTexture(s, paint.getMask(i));
1827 target->setSamplerState(s, *paint.getMaskSampler(i));
1828 }
1829
bsalomon@google.com27847de2011-02-22 20:59:41 +00001830 target->setColor(paint.fColor);
1831
1832 if (paint.fDither) {
1833 target->enableState(GrDrawTarget::kDither_StateBit);
1834 } else {
1835 target->disableState(GrDrawTarget::kDither_StateBit);
1836 }
1837 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001838 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001839 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001840 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001841 }
1842 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001843 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001844
1845 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1846 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1847 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001848}
1849
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001850GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001851 DrawCategory category) {
1852 if (category != fLastDrawCategory) {
1853 flushDrawBuffer();
1854 fLastDrawCategory = category;
1855 }
1856 SetPaint(paint, fGpu);
1857 GrDrawTarget* target = fGpu;
1858 switch (category) {
1859 case kText_DrawCategory:
1860#if DEFER_TEXT_RENDERING
1861 target = fDrawBuffer;
1862 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1863#else
1864 target = fGpu;
1865#endif
1866 break;
1867 case kUnbuffered_DrawCategory:
1868 target = fGpu;
1869 break;
1870 case kBuffered_DrawCategory:
1871 target = fDrawBuffer;
1872 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1873 break;
1874 }
1875 return target;
1876}
1877
bsalomon@google.com289533a2011-10-27 12:34:25 +00001878GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1879 GrPathFill fill,
1880 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001881 if (NULL == fPathRendererChain) {
1882 fPathRendererChain =
1883 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1884 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001885 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1886 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001887}
1888
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889////////////////////////////////////////////////////////////////////////////////
1890
bsalomon@google.com27847de2011-02-22 20:59:41 +00001891void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001892 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001893 fGpu->setRenderTarget(target);
1894}
1895
1896GrRenderTarget* GrContext::getRenderTarget() {
1897 return fGpu->getRenderTarget();
1898}
1899
1900const GrRenderTarget* GrContext::getRenderTarget() const {
1901 return fGpu->getRenderTarget();
1902}
1903
1904const GrMatrix& GrContext::getMatrix() const {
1905 return fGpu->getViewMatrix();
1906}
1907
1908void GrContext::setMatrix(const GrMatrix& m) {
1909 fGpu->setViewMatrix(m);
1910}
1911
1912void GrContext::concatMatrix(const GrMatrix& m) const {
1913 fGpu->preConcatViewMatrix(m);
1914}
1915
1916static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1917 intptr_t mask = 1 << shift;
1918 if (pred) {
1919 bits |= mask;
1920 } else {
1921 bits &= ~mask;
1922 }
1923 return bits;
1924}
1925
1926void GrContext::resetStats() {
1927 fGpu->resetStats();
1928}
1929
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001930const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001931 return fGpu->getStats();
1932}
1933
1934void GrContext::printStats() const {
1935 fGpu->printStats();
1936}
1937
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001938GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001939 fGpu = gpu;
1940 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001941 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001942
bsalomon@google.com30085192011-08-19 15:42:31 +00001943 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001944
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001945 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1946 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001947 fFontCache = new GrFontCache(fGpu);
1948
1949 fLastDrawCategory = kUnbuffered_DrawCategory;
1950
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001951 fDrawBuffer = NULL;
1952 fDrawBufferVBAllocPool = NULL;
1953 fDrawBufferIBAllocPool = NULL;
1954
bsalomon@google.com205d4602011-04-25 12:43:45 +00001955 fAAFillRectIndexBuffer = NULL;
1956 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001957
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001958 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1959 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001960 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1961 }
1962 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001963
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001964 this->setupDrawBuffer();
1965}
1966
1967void GrContext::setupDrawBuffer() {
1968
1969 GrAssert(NULL == fDrawBuffer);
1970 GrAssert(NULL == fDrawBufferVBAllocPool);
1971 GrAssert(NULL == fDrawBufferIBAllocPool);
1972
bsalomon@google.com27847de2011-02-22 20:59:41 +00001973#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001974 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001975 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001976 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1977 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001978 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001979 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001980 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001981 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1982
bsalomon@google.com471d4712011-08-23 15:45:25 +00001983 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1984 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001985 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001986#endif
1987
1988#if BATCH_RECT_TO_RECT
1989 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1990#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001991}
1992
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1994 GrDrawTarget* target;
1995#if DEFER_TEXT_RENDERING
1996 target = prepareToDraw(paint, kText_DrawCategory);
1997#else
1998 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1999#endif
2000 SetPaint(paint, target);
2001 return target;
2002}
2003
2004const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2005 return fGpu->getQuadIndexBuffer();
2006}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002007
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002008void GrContext::convolveInX(GrTexture* texture,
2009 const SkRect& rect,
2010 const float* kernel,
2011 int kernelWidth) {
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002012 float imageIncrement[2] = {1.0f / texture->allocatedWidth(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002013 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2014}
2015
2016void GrContext::convolveInY(GrTexture* texture,
2017 const SkRect& rect,
2018 const float* kernel,
2019 int kernelWidth) {
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002020 float imageIncrement[2] = {0.0f, 1.0f / texture->allocatedHeight()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002021 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2022}
2023
2024void GrContext::convolve(GrTexture* texture,
2025 const SkRect& rect,
2026 float imageIncrement[2],
2027 const float* kernel,
2028 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002029 GrDrawTarget::AutoStateRestore asr(fGpu);
2030 GrMatrix sampleM;
2031 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
2032 GrSamplerState::kClamp_WrapMode,
2033 GrSamplerState::kConvolution_Filter);
2034 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002035 sampleM.setIDiv(texture->width(), 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.org60014ca2011-11-09 16:05:58 +00002040 fGpu->setColor(0xFFFFFFFF);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002041 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002042 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2043}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002044
2045///////////////////////////////////////////////////////////////////////////////