blob: fe85b97b92dc0a6820f517454f9e62cf61573661 [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
bsalomon@google.com27847de2011-02-22 20:59:41 +000058GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000059 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000060 delete fTextureCache;
61 delete fFontCache;
62 delete fDrawBuffer;
63 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000064 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000065
bsalomon@google.com205d4602011-04-25 12:43:45 +000066 GrSafeUnref(fAAFillRectIndexBuffer);
67 GrSafeUnref(fAAStrokeRectIndexBuffer);
68 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000069 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000070}
71
bsalomon@google.com8fe72472011-03-30 21:26:44 +000072void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000073 contextDestroyed();
74 this->setupDrawBuffer();
75}
76
77void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000078 // abandon first to so destructors
79 // don't try to free the resources in the API.
80 fGpu->abandonResources();
81
bsalomon@google.com30085192011-08-19 15:42:31 +000082 // a path renderer may be holding onto resources that
83 // are now unusable
84 GrSafeSetNull(fPathRendererChain);
85
bsalomon@google.com8fe72472011-03-30 21:26:44 +000086 delete fDrawBuffer;
87 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000088
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBufferVBAllocPool;
90 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferIBAllocPool;
93 fDrawBufferIBAllocPool = NULL;
94
bsalomon@google.com205d4602011-04-25 12:43:45 +000095 GrSafeSetNull(fAAFillRectIndexBuffer);
96 GrSafeSetNull(fAAStrokeRectIndexBuffer);
97
bsalomon@google.com8fe72472011-03-30 21:26:44 +000098 fTextureCache->removeAll();
99 fFontCache->freeAll();
100 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101}
102
103void GrContext::resetContext() {
104 fGpu->markContextDirty();
105}
106
107void GrContext::freeGpuResources() {
108 this->flush();
109 fTextureCache->removeAll();
110 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000111 // a path renderer may be holding onto resources
112 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000113}
114
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000115////////////////////////////////////////////////////////////////////////////////
116
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000117int GrContext::PaintStageVertexLayoutBits(
118 const GrPaint& paint,
119 const bool hasTexCoords[GrPaint::kTotalStages]) {
120 int stageMask = paint.getActiveStageMask();
121 int layout = 0;
122 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
123 if ((1 << i) & stageMask) {
124 if (NULL != hasTexCoords && hasTexCoords[i]) {
125 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
126 } else {
127 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
128 }
129 }
130 }
131 return layout;
132}
133
134
135////////////////////////////////////////////////////////////////////////////////
136
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000137enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000138 // flags for textures
139 kNPOTBit = 0x1,
140 kFilterBit = 0x2,
141 kScratchBit = 0x4,
142
143 // resource type
144 kTextureBit = 0x8,
145 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000146};
147
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000148GrTexture* GrContext::TextureCacheEntry::texture() const {
149 if (NULL == fEntry) {
150 return NULL;
151 } else {
152 return (GrTexture*) fEntry->resource();
153 }
154}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000155
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000156namespace {
157// returns true if this is a "special" texture because of gpu NPOT limitations
158bool gen_texture_key_values(const GrGpu* gpu,
159 const GrSamplerState& sampler,
160 GrContext::TextureKey clientKey,
161 int width,
162 int height,
163 bool scratch,
164 uint32_t v[4]) {
165 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
166 // we assume we only need 16 bits of width and height
167 // assert that texture creation will fail anyway if this assumption
168 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000169 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000170 v[0] = clientKey & 0xffffffffUL;
171 v[1] = (clientKey >> 32) & 0xffffffffUL;
172 v[2] = width | (height << 16);
173
174 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000175 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000176 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
177
178 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
179 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
180
181 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000182 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000183 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000184 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000185 }
186 }
187 }
188
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000189 if (scratch) {
190 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000191 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000192
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000193 v[3] |= kTextureBit;
194
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000195 return v[3] & kNPOTBit;
196}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197
198// we should never have more than one stencil buffer with same combo of
199// (width,height,samplecount)
200void gen_stencil_key_values(int width, int height,
201 int sampleCnt, uint32_t v[4]) {
202 v[0] = width;
203 v[1] = height;
204 v[2] = sampleCnt;
205 v[3] = kStencilBufferBit;
206}
207
208void gen_stencil_key_values(const GrStencilBuffer* sb,
209 uint32_t v[4]) {
210 gen_stencil_key_values(sb->width(), sb->height(),
211 sb->numSamples(), v);
212}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000213
214// This should be subsumed by a future version of GrDrawState
215// It does not reset stage textures/samplers or per-vertex-edge-aa state since
216// they aren't used unless the vertex layout references them.
217// It also doesn't set the render target.
218void reset_target_state(GrDrawTarget* target){
219 target->setViewMatrix(GrMatrix::I());
220 target->setColorFilter(0, SkXfermode::kDst_Mode);
221 target->disableState(GrDrawTarget::kDither_StateBit |
222 GrDrawTarget::kHWAntialias_StateBit |
223 GrDrawTarget::kClip_StateBit |
224 GrDrawTarget::kNoColorWrites_StateBit |
225 GrDrawTarget::kEdgeAAConcave_StateBit);
226 target->setEdgeAAData(NULL, 0);
227 target->disableStencil();
228 target->setAlpha(0xFF);
229 target->setBlendFunc(kOne_BlendCoeff,
230 kZero_BlendCoeff);
231 target->setFirstCoverageStage(GrDrawState::kNumStages);
232 target->setDrawFace(GrDrawState::kBoth_DrawFace);
233}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000234}
235
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000236GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
237 int width,
238 int height,
239 const GrSamplerState& sampler) {
240 uint32_t v[4];
241 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
242 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000243 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
244 GrResourceCache::kNested_LockType));
245}
246
247GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
248 uint32_t v[4];
249 gen_stencil_key_values(sb, v);
250 GrResourceKey resourceKey(v);
251 return fTextureCache->createAndLock(resourceKey, sb);
252}
253
254GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
255 int sampleCnt) {
256 uint32_t v[4];
257 gen_stencil_key_values(width, height, sampleCnt, v);
258 GrResourceKey resourceKey(v);
259 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
260 GrResourceCache::kSingle_LockType);
261 if (NULL != entry) {
262 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
263 return sb;
264 } else {
265 return NULL;
266 }
267}
268
269void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
270 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000271}
272
273static void stretchImage(void* dst,
274 int dstW,
275 int dstH,
276 void* src,
277 int srcW,
278 int srcH,
279 int bpp) {
280 GrFixed dx = (srcW << 16) / dstW;
281 GrFixed dy = (srcH << 16) / dstH;
282
283 GrFixed y = dy >> 1;
284
285 int dstXLimit = dstW*bpp;
286 for (int j = 0; j < dstH; ++j) {
287 GrFixed x = dx >> 1;
288 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
289 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
290 for (int i = 0; i < dstXLimit; i += bpp) {
291 memcpy((uint8_t*) dstRow + i,
292 (uint8_t*) srcRow + (x>>16)*bpp,
293 bpp);
294 x += dx;
295 }
296 y += dy;
297 }
298}
299
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000300GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000301 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000302 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000303 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000304 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000305
306#if GR_DUMP_TEXTURE_UPLOAD
307 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
308#endif
309
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000310 TextureCacheEntry entry;
311 uint32_t v[4];
312 bool special = gen_texture_key_values(fGpu, sampler, key,
313 desc.fWidth, desc.fHeight, false, v);
314 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000315
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000316 if (special) {
317 TextureCacheEntry clampEntry =
318 findAndLockTexture(key, desc.fWidth, desc.fHeight,
319 GrSamplerState::ClampNoFilter());
320
321 if (NULL == clampEntry.texture()) {
322 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000323 GrSamplerState::ClampNoFilter(),
324 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000325 GrAssert(NULL != clampEntry.texture());
326 if (NULL == clampEntry.texture()) {
327 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000328 }
329 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000330 GrTextureDesc rtDesc = desc;
331 rtDesc.fFlags = rtDesc.fFlags |
332 kRenderTarget_GrTextureFlagBit |
333 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000334 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
335 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000336
337 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
338
339 if (NULL != texture) {
340 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000341 reset_target_state(fGpu);
342
bsalomon@google.com27847de2011-02-22 20:59:41 +0000343 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000344 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000345
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000346 GrSamplerState::Filter filter;
347 // if filtering is not desired then we want to ensure all
348 // texels in the resampled image are copies of texels from
349 // the original.
350 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
351 filter = GrSamplerState::kNearest_Filter;
352 } else {
353 filter = GrSamplerState::kBilinear_Filter;
354 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000355 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
356 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000357 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000358 fGpu->setSamplerState(0, stretchSampler);
359
360 static const GrVertexLayout layout =
361 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
362 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
363
364 if (arg.succeeded()) {
365 GrPoint* verts = (GrPoint*) arg.vertices();
366 verts[0].setIRectFan(0, 0,
367 texture->width(),
368 texture->height(),
369 2*sizeof(GrPoint));
370 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
371 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
372 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000373 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000374 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000375 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000376 } else {
377 // TODO: Our CPU stretch doesn't filter. But we create separate
378 // stretched textures when the sampler state is either filtered or
379 // not. Either implement filtered stretch blit on CPU or just create
380 // one when FBO case fails.
381
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000382 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000383 // no longer need to clamp at min RT size.
384 rtDesc.fWidth = GrNextPow2(desc.fWidth);
385 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000386 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000387 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000388 rtDesc.fWidth *
389 rtDesc.fHeight);
390 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
391 srcData, desc.fWidth, desc.fHeight, bpp);
392
393 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
394
395 GrTexture* texture = fGpu->createTexture(rtDesc,
396 stretchedPixels.get(),
397 stretchedRowBytes);
398 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000399 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000400 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000401 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402
403 } else {
404 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
405 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000406 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000407 }
408 }
409 return entry;
410}
411
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412namespace {
413inline void gen_scratch_tex_key_values(const GrGpu* gpu,
414 const GrTextureDesc& desc,
415 uint32_t v[4]) {
416 // Instead of a client-provided key of the texture contents
417 // we create a key of from the descriptor.
418 GrContext::TextureKey descKey = desc.fAALevel |
419 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000420 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421 // this code path isn't friendly to tiling with NPOT restricitons
422 // We just pass ClampNoFilter()
423 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
424 desc.fWidth, desc.fHeight, true, v);
425}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000426}
427
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000428GrContext::TextureCacheEntry GrContext::lockScratchTexture(
429 const GrTextureDesc& inDesc,
430 ScratchTexMatch match) {
431
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000432 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000433 if (kExact_ScratchTexMatch != match) {
434 // bin by pow2 with a reasonable min
435 static const int MIN_SIZE = 256;
436 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
437 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
438 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000439
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000440 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000441 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
442
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000443 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000444 int origWidth = desc.fWidth;
445 int origHeight = desc.fHeight;
446 bool doubledW = false;
447 bool doubledH = false;
448
449 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000450 uint32_t v[4];
451 gen_scratch_tex_key_values(fGpu, desc, v);
452 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000453 entry = fTextureCache->findAndLock(key,
454 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000455 // if we miss, relax the fit of the flags...
456 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000457 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000458 break;
459 }
460 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
461 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
462 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
463 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
464 } else if (!doubledW) {
465 desc.fFlags = inDesc.fFlags;
466 desc.fWidth *= 2;
467 doubledW = true;
468 } else if (!doubledH) {
469 desc.fFlags = inDesc.fFlags;
470 desc.fWidth = origWidth;
471 desc.fHeight *= 2;
472 doubledH = true;
473 } else {
474 break;
475 }
476
477 } while (true);
478
479 if (NULL == entry) {
480 desc.fFlags = inDesc.fFlags;
481 desc.fWidth = origWidth;
482 desc.fHeight = origHeight;
483 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
484 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000485 uint32_t v[4];
486 gen_scratch_tex_key_values(fGpu, desc, v);
487 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000488 entry = fTextureCache->createAndLock(key, texture);
489 }
490 }
491
492 // If the caller gives us the same desc/sampler twice we don't want
493 // to return the same texture the second time (unless it was previously
494 // released). So we detach the entry from the cache and reattach at release.
495 if (NULL != entry) {
496 fTextureCache->detach(entry);
497 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000498 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000499}
500
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000501void GrContext::unlockTexture(TextureCacheEntry entry) {
502 // If this is a scratch texture we detached it from the cache
503 // while it was locked (to avoid two callers simultaneously getting
504 // the same texture).
505 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
506 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000507 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000508 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000509 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000510}
511
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000512GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000513 void* srcData,
514 size_t rowBytes) {
515 return fGpu->createTexture(desc, srcData, rowBytes);
516}
517
518void GrContext::getTextureCacheLimits(int* maxTextures,
519 size_t* maxTextureBytes) const {
520 fTextureCache->getLimits(maxTextures, maxTextureBytes);
521}
522
523void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
524 fTextureCache->setLimits(maxTextures, maxTextureBytes);
525}
526
bsalomon@google.com91958362011-06-13 17:58:13 +0000527int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000528 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000529}
530
531int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000532 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000533}
534
535///////////////////////////////////////////////////////////////////////////////
536
bsalomon@google.come269f212011-11-07 13:29:52 +0000537GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
538 return fGpu->createPlatformTexture(desc);
539}
540
541GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
542 return fGpu->createPlatformRenderTarget(desc);
543}
544
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000545GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
546 // validate flags here so that GrGpu subclasses don't have to check
547 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
548 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000549 return NULL;
550 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000551 if (desc.fSampleCnt &&
552 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000553 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000554 }
555 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
556 desc.fSampleCnt &&
557 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
558 return NULL;
559 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000560 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000561}
562
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000563///////////////////////////////////////////////////////////////////////////////
564
bsalomon@google.com27847de2011-02-22 20:59:41 +0000565bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000566 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000567 const GrDrawTarget::Caps& caps = fGpu->getCaps();
568 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000569 return false;
570 }
571
bsalomon@google.com27847de2011-02-22 20:59:41 +0000572 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
573
574 if (!isPow2) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000575 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
576 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000577 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000578 return false;
579 }
580 }
581 return true;
582}
583
584////////////////////////////////////////////////////////////////////////////////
585
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000586const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
587
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588void GrContext::setClip(const GrClip& clip) {
589 fGpu->setClip(clip);
590 fGpu->enableState(GrDrawTarget::kClip_StateBit);
591}
592
593void GrContext::setClip(const GrIRect& rect) {
594 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000595 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596 fGpu->setClip(clip);
597}
598
599////////////////////////////////////////////////////////////////////////////////
600
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000601void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000602 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000603 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000604}
605
606void GrContext::drawPaint(const GrPaint& paint) {
607 // set rect to be big enough to fill the space, but not super-huge, so we
608 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000609 GrRect r;
610 r.setLTRB(0, 0,
611 GrIntToScalar(getRenderTarget()->width()),
612 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000613 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000614 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000615 SkTLazy<GrPaint> tmpPaint;
616 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000617 // We attempt to map r by the inverse matrix and draw that. mapRect will
618 // map the four corners and bound them with a new rect. This will not
619 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000620 if (!this->getMatrix().hasPerspective()) {
621 if (!fGpu->getViewInverse(&inverse)) {
622 GrPrintf("Could not invert matrix");
623 return;
624 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000625 inverse.mapRect(&r);
626 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000627 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
628 if (!fGpu->getViewInverse(&inverse)) {
629 GrPrintf("Could not invert matrix");
630 return;
631 }
632 tmpPaint.set(paint);
633 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
634 p = tmpPaint.get();
635 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000636 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000637 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000638 // by definition this fills the entire clip, no need for AA
639 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000640 if (!tmpPaint.isValid()) {
641 tmpPaint.set(paint);
642 p = tmpPaint.get();
643 }
644 GrAssert(p == tmpPaint.get());
645 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000646 }
647 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000648}
649
bsalomon@google.com205d4602011-04-25 12:43:45 +0000650////////////////////////////////////////////////////////////////////////////////
651
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000652namespace {
653inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
654 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
655}
656}
657
bsalomon@google.com91958362011-06-13 17:58:13 +0000658struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000659 enum Downsample {
660 k4x4TwoPass_Downsample,
661 k4x4SinglePass_Downsample,
662 kFSAA_Downsample
663 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000664 int fTileSizeX;
665 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000666 int fTileCountX;
667 int fTileCountY;
668 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000669 GrAutoScratchTexture fOffscreen0;
670 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000671 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000672 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000673};
674
bsalomon@google.com471d4712011-08-23 15:45:25 +0000675bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000676 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000677#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000678 return false;
679#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000680 // Line primitves are always rasterized as 1 pixel wide.
681 // Super-sampling would make them too thin but MSAA would be OK.
682 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000683 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000684 return false;
685 }
686 if (target->getRenderTarget()->isMultisampled()) {
687 return false;
688 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000689 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000690#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000691 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000692#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000693 return false;
694 }
695 return true;
696#endif
697}
698
bsalomon@google.com91958362011-06-13 17:58:13 +0000699bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000700 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000701 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000702 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000703 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000704
705 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000706
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000707 GrAssert(NULL == record->fOffscreen0.texture());
708 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000709 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000710
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000711 int boundW = boundRect.width();
712 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000713
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000714 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000715
716 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
717 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
718
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000719 if (requireStencil) {
720 desc.fFlags = kRenderTarget_GrTextureFlagBit;
721 } else {
722 desc.fFlags = kRenderTarget_GrTextureFlagBit |
723 kNoStencil_GrTextureFlagBit;
724 }
725
bsalomon@google.comc4364992011-11-07 15:54:49 +0000726 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000727
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000728 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000729 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000730 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000731 desc.fAALevel = kMed_GrAALevel;
732 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000733 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000734 OffscreenRecord::k4x4SinglePass_Downsample :
735 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000736 record->fScale = OFFSCREEN_SSAA_SCALE;
737 // both downsample paths assume this
738 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000739 desc.fAALevel = kNone_GrAALevel;
740 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000741
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000742 desc.fWidth *= record->fScale;
743 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000744 record->fOffscreen0.set(this, desc);
745 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000746 return false;
747 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000748 // the approximate lookup might have given us some slop space, might as well
749 // use it when computing the tiles size.
750 // these are scale values, will adjust after considering
751 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000752 record->fTileSizeX = record->fOffscreen0.texture()->width();
753 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000754
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000755 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000756 desc.fWidth /= 2;
757 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000758 record->fOffscreen1.set(this, desc);
759 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000760 return false;
761 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000762 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000763 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000764 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000765 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000766 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000767 record->fTileSizeX /= record->fScale;
768 record->fTileSizeY /= record->fScale;
769
770 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
771 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
772
tomhudson@google.com237a4612011-07-19 15:44:00 +0000773 record->fClip = target->getClip();
774
bsalomon@google.com91958362011-06-13 17:58:13 +0000775 target->saveCurrentDrawState(&record->fSavedState);
776 return true;
777}
778
779void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
780 const GrIRect& boundRect,
781 int tileX, int tileY,
782 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000783
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000784 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000785 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000786
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000787 GrPaint tempPaint;
788 tempPaint.reset();
789 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000790 target->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000791#if PREFER_MSAA_OFFSCREEN_AA
792 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
793#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000794
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000796 int left = boundRect.fLeft + tileX * record->fTileSizeX;
797 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000798 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000799 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000800 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000801 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000802 target->postConcatViewMatrix(scaleM);
803
bsalomon@google.com91958362011-06-13 17:58:13 +0000804 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000805 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000806 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000807 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000808 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
809 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000810 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000811#if 0
812 // visualize tile boundaries by setting edges of offscreen to white
813 // and interior to tranparent. black.
814 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000815
bsalomon@google.com91958362011-06-13 17:58:13 +0000816 static const int gOffset = 2;
817 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
818 record->fScale * w - gOffset,
819 record->fScale * h - gOffset);
820 target->clear(&clear2, 0x0);
821#else
822 target->clear(&clear, 0x0);
823#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000824}
825
bsalomon@google.com91958362011-06-13 17:58:13 +0000826void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000827 const GrPaint& paint,
828 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000829 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000830 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000831 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000832 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000833 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000834 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000835 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
836 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000837 tileRect.fRight = (tileX == record->fTileCountX-1) ?
838 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000839 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000840 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
841 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000842 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000843
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000844 GrSamplerState::Filter filter;
845 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
846 filter = GrSamplerState::k4x4Downsample_Filter;
847 } else {
848 filter = GrSamplerState::kBilinear_Filter;
849 }
850
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000851 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000852 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000853 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000854
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000855 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000856 int scale;
857
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000858 enum {
859 kOffscreenStage = GrPaint::kTotalStages,
860 };
861
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000862 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000863 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000865 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000866
867 // Do 2x2 downsample from first to second
868 target->setTexture(kOffscreenStage, src);
869 target->setRenderTarget(dst);
870 target->setViewMatrix(GrMatrix::I());
871 sampleM.setScale(scale * GR_Scalar1 / src->width(),
872 scale * GR_Scalar1 / src->height());
873 sampler.setMatrix(sampleM);
874 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000875 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
876 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000877 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
878
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000879 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000880 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000881 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000882 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000883 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000884 } else {
885 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
886 record->fDownsample);
887 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000888 }
889
bsalomon@google.com91958362011-06-13 17:58:13 +0000890 // setup for draw back to main RT, we use the original
891 // draw state setup by the caller plus an additional coverage
892 // stage to handle the AA resolve. Also, we use an identity
893 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000894 int stageMask = paint.getActiveStageMask();
895
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000896 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000897 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000898
899 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000900 GrMatrix invVM;
901 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000902 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000903 }
904 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000905 // This is important when tiling, otherwise second tile's
906 // pass 1 view matrix will be incorrect.
907 GrDrawTarget::AutoViewMatrixRestore avmr(target);
908
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000909 target->setViewMatrix(GrMatrix::I());
910
911 target->setTexture(kOffscreenStage, src);
912 sampleM.setScale(scale * GR_Scalar1 / src->width(),
913 scale * GR_Scalar1 / src->height());
914 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000915 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
916 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000917 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000918 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000919
reed@google.com20efde72011-05-09 17:00:02 +0000920 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000921 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000922 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000923 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000924}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000925
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000926void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
927 GrPathRenderer* pr,
928 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000929 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000930}
931
932////////////////////////////////////////////////////////////////////////////////
933
bsalomon@google.com27847de2011-02-22 20:59:41 +0000934/* create a triangle strip that strokes the specified triangle. There are 8
935 unique vertices, but we repreat the last 2 to close up. Alternatively we
936 could use an indices array, and then only send 8 verts, but not sure that
937 would be faster.
938 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000939static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000940 GrScalar width) {
941 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000942 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000943
944 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
945 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
946 verts[2].set(rect.fRight - rad, rect.fTop + rad);
947 verts[3].set(rect.fRight + rad, rect.fTop - rad);
948 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
949 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
950 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
951 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
952 verts[8] = verts[0];
953 verts[9] = verts[1];
954}
955
bsalomon@google.com205d4602011-04-25 12:43:45 +0000956static void setInsetFan(GrPoint* pts, size_t stride,
957 const GrRect& r, GrScalar dx, GrScalar dy) {
958 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
959}
960
961static const uint16_t gFillAARectIdx[] = {
962 0, 1, 5, 5, 4, 0,
963 1, 2, 6, 6, 5, 1,
964 2, 3, 7, 7, 6, 2,
965 3, 0, 4, 4, 7, 3,
966 4, 5, 6, 6, 7, 4,
967};
968
969int GrContext::aaFillRectIndexCount() const {
970 return GR_ARRAY_COUNT(gFillAARectIdx);
971}
972
973GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
974 if (NULL == fAAFillRectIndexBuffer) {
975 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
976 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000977 if (NULL != fAAFillRectIndexBuffer) {
978 #if GR_DEBUG
979 bool updated =
980 #endif
981 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
982 sizeof(gFillAARectIdx));
983 GR_DEBUGASSERT(updated);
984 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000985 }
986 return fAAFillRectIndexBuffer;
987}
988
989static const uint16_t gStrokeAARectIdx[] = {
990 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
991 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
992 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
993 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
994
995 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
996 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
997 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
998 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
999
1000 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1001 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1002 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1003 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1004};
1005
1006int GrContext::aaStrokeRectIndexCount() const {
1007 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1008}
1009
1010GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1011 if (NULL == fAAStrokeRectIndexBuffer) {
1012 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1013 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001014 if (NULL != fAAStrokeRectIndexBuffer) {
1015 #if GR_DEBUG
1016 bool updated =
1017 #endif
1018 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1019 sizeof(gStrokeAARectIdx));
1020 GR_DEBUGASSERT(updated);
1021 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001022 }
1023 return fAAStrokeRectIndexBuffer;
1024}
1025
bsalomon@google.coma3108262011-10-10 14:08:47 +00001026static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1027 bool useCoverage) {
1028 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001029 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001030 if (NULL != target->getTexture(s)) {
1031 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1032 }
1033 }
1034 if (useCoverage) {
1035 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1036 } else {
1037 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1038 }
1039 return layout;
1040}
1041
bsalomon@google.com205d4602011-04-25 12:43:45 +00001042void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001043 const GrRect& devRect,
1044 bool useVertexCoverage) {
1045 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001046
1047 size_t vsize = GrDrawTarget::VertexSize(layout);
1048
1049 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001050 if (!geo.succeeded()) {
1051 GrPrintf("Failed to get space for vertices!\n");
1052 return;
1053 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001054 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1055 if (NULL == indexBuffer) {
1056 GrPrintf("Failed to create index buffer!\n");
1057 return;
1058 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001059
1060 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1061
1062 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1063 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1064
1065 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1066 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1067
1068 verts += sizeof(GrPoint);
1069 for (int i = 0; i < 4; ++i) {
1070 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1071 }
1072
bsalomon@google.coma3108262011-10-10 14:08:47 +00001073 GrColor innerColor;
1074 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001075 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001076 } else {
1077 innerColor = target->getColor();
1078 }
1079
bsalomon@google.com205d4602011-04-25 12:43:45 +00001080 verts += 4 * vsize;
1081 for (int i = 0; i < 4; ++i) {
1082 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1083 }
1084
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001085 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001086
1087 target->drawIndexed(kTriangles_PrimitiveType, 0,
1088 0, 8, this->aaFillRectIndexCount());
1089}
1090
bsalomon@google.coma3108262011-10-10 14:08:47 +00001091void GrContext::strokeAARect(GrDrawTarget* target,
1092 const GrRect& devRect,
1093 const GrVec& devStrokeSize,
1094 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001095 const GrScalar& dx = devStrokeSize.fX;
1096 const GrScalar& dy = devStrokeSize.fY;
1097 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1098 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1099
bsalomon@google.com205d4602011-04-25 12:43:45 +00001100 GrScalar spare;
1101 {
1102 GrScalar w = devRect.width() - dx;
1103 GrScalar h = devRect.height() - dy;
1104 spare = GrMin(w, h);
1105 }
1106
1107 if (spare <= 0) {
1108 GrRect r(devRect);
1109 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001110 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001111 return;
1112 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001113 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001114 size_t vsize = GrDrawTarget::VertexSize(layout);
1115
1116 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001117 if (!geo.succeeded()) {
1118 GrPrintf("Failed to get space for vertices!\n");
1119 return;
1120 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001121 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1122 if (NULL == indexBuffer) {
1123 GrPrintf("Failed to create index buffer!\n");
1124 return;
1125 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001126
1127 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1128
1129 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1130 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1131 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1132 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1133
1134 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1135 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1136 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1137 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1138
1139 verts += sizeof(GrPoint);
1140 for (int i = 0; i < 4; ++i) {
1141 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1142 }
1143
bsalomon@google.coma3108262011-10-10 14:08:47 +00001144 GrColor innerColor;
1145 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001146 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001147 } else {
1148 innerColor = target->getColor();
1149 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001150 verts += 4 * vsize;
1151 for (int i = 0; i < 8; ++i) {
1152 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1153 }
1154
1155 verts += 8 * vsize;
1156 for (int i = 0; i < 8; ++i) {
1157 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1158 }
1159
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001160 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001161 target->drawIndexed(kTriangles_PrimitiveType,
1162 0, 0, 16, aaStrokeRectIndexCount());
1163}
1164
reed@google.com20efde72011-05-09 17:00:02 +00001165/**
1166 * Returns true if the rects edges are integer-aligned.
1167 */
1168static bool isIRect(const GrRect& r) {
1169 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1170 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1171}
1172
bsalomon@google.com205d4602011-04-25 12:43:45 +00001173static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001174 const GrRect& rect,
1175 GrScalar width,
1176 const GrMatrix* matrix,
1177 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001178 GrRect* devRect,
1179 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001180 // we use a simple alpha ramp to do aa on axis-aligned rects
1181 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001182 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001183
bsalomon@google.coma3108262011-10-10 14:08:47 +00001184 // we are keeping around the "tweak the alpha" trick because
1185 // it is our only hope for the fixed-pipe implementation.
1186 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001187 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001188 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001189 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001190 if (target->getCaps().fSupportPerVertexCoverage) {
1191 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001192#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001193 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001194#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001195 return false;
1196 } else {
1197 *useVertexCoverage = true;
1198 }
1199 } else {
1200 GrPrintf("Rect AA dropped because no support for coverage.\n");
1201 return false;
1202 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001203 }
1204
1205 if (target->getRenderTarget()->isMultisampled()) {
1206 return false;
1207 }
1208
bsalomon@google.com471d4712011-08-23 15:45:25 +00001209 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001210 return false;
1211 }
1212
1213 if (!target->getViewMatrix().preservesAxisAlignment()) {
1214 return false;
1215 }
1216
1217 if (NULL != matrix &&
1218 !matrix->preservesAxisAlignment()) {
1219 return false;
1220 }
1221
1222 *combinedMatrix = target->getViewMatrix();
1223 if (NULL != matrix) {
1224 combinedMatrix->preConcat(*matrix);
1225 GrAssert(combinedMatrix->preservesAxisAlignment());
1226 }
1227
1228 combinedMatrix->mapRect(devRect, rect);
1229 devRect->sort();
1230
1231 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001232 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001233 } else {
1234 return true;
1235 }
1236}
1237
bsalomon@google.com27847de2011-02-22 20:59:41 +00001238void GrContext::drawRect(const GrPaint& paint,
1239 const GrRect& rect,
1240 GrScalar width,
1241 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001242 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001243
1244 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001245 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001246
bsalomon@google.com205d4602011-04-25 12:43:45 +00001247 GrRect devRect = rect;
1248 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001249 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001250 bool needAA = paint.fAntiAlias &&
1251 !this->getRenderTarget()->isMultisampled();
1252 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1253 &combinedMatrix, &devRect,
1254 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001255
1256 if (doAA) {
1257 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001258 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001259 GrMatrix inv;
1260 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001261 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001262 }
1263 }
1264 target->setViewMatrix(GrMatrix::I());
1265 if (width >= 0) {
1266 GrVec strokeSize;;
1267 if (width > 0) {
1268 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001269 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001270 strokeSize.setAbs(strokeSize);
1271 } else {
1272 strokeSize.set(GR_Scalar1, GR_Scalar1);
1273 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001274 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001275 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001276 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001277 }
1278 return;
1279 }
1280
bsalomon@google.com27847de2011-02-22 20:59:41 +00001281 if (width >= 0) {
1282 // TODO: consider making static vertex buffers for these cases.
1283 // Hairline could be done by just adding closing vertex to
1284 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001285 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1286
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 static const int worstCaseVertCount = 10;
1288 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1289
1290 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001291 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292 return;
1293 }
1294
1295 GrPrimitiveType primType;
1296 int vertCount;
1297 GrPoint* vertex = geo.positions();
1298
1299 if (width > 0) {
1300 vertCount = 10;
1301 primType = kTriangleStrip_PrimitiveType;
1302 setStrokeRectStrip(vertex, rect, width);
1303 } else {
1304 // hairline
1305 vertCount = 5;
1306 primType = kLineStrip_PrimitiveType;
1307 vertex[0].set(rect.fLeft, rect.fTop);
1308 vertex[1].set(rect.fRight, rect.fTop);
1309 vertex[2].set(rect.fRight, rect.fBottom);
1310 vertex[3].set(rect.fLeft, rect.fBottom);
1311 vertex[4].set(rect.fLeft, rect.fTop);
1312 }
1313
1314 GrDrawTarget::AutoViewMatrixRestore avmr;
1315 if (NULL != matrix) {
1316 avmr.set(target);
1317 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001318 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001319 }
1320
1321 target->drawNonIndexed(primType, 0, vertCount);
1322 } else {
1323 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001324 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001325 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1326 if (NULL == sqVB) {
1327 GrPrintf("Failed to create static rect vb.\n");
1328 return;
1329 }
1330 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1332 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001333 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001334 0, rect.height(), rect.fTop,
1335 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001336
1337 if (NULL != matrix) {
1338 m.postConcat(*matrix);
1339 }
1340
1341 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001342 target->preConcatSamplerMatrices(stageMask, m);
1343
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1345 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001346 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001347 #endif
1348 }
1349}
1350
1351void GrContext::drawRectToRect(const GrPaint& paint,
1352 const GrRect& dstRect,
1353 const GrRect& srcRect,
1354 const GrMatrix* dstMatrix,
1355 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001356 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001357
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001358 // srcRect refers to paint's first texture
1359 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001360 drawRect(paint, dstRect, -1, dstMatrix);
1361 return;
1362 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001363
bsalomon@google.com27847de2011-02-22 20:59:41 +00001364 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1365
1366#if GR_STATIC_RECT_VB
1367 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001368
1369 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001370 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1371
1372 GrMatrix m;
1373
1374 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1375 0, dstRect.height(), dstRect.fTop,
1376 0, 0, GrMatrix::I()[8]);
1377 if (NULL != dstMatrix) {
1378 m.postConcat(*dstMatrix);
1379 }
1380 target->preConcatViewMatrix(m);
1381
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001382 // srcRect refers to first stage
1383 int otherStageMask = paint.getActiveStageMask() &
1384 (~(1 << GrPaint::kFirstTextureStage));
1385 if (otherStageMask) {
1386 target->preConcatSamplerMatrices(otherStageMask, m);
1387 }
1388
bsalomon@google.com27847de2011-02-22 20:59:41 +00001389 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1390 0, srcRect.height(), srcRect.fTop,
1391 0, 0, GrMatrix::I()[8]);
1392 if (NULL != srcMatrix) {
1393 m.postConcat(*srcMatrix);
1394 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001395 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001396
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001397 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1398 if (NULL == sqVB) {
1399 GrPrintf("Failed to create static rect vb.\n");
1400 return;
1401 }
1402 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001403 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1404#else
1405
1406 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001407#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001408 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001409#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1411#endif
1412
tomhudson@google.com93813632011-10-27 20:21:16 +00001413 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1414 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 srcRects[0] = &srcRect;
1416 srcMatrices[0] = srcMatrix;
1417
1418 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1419#endif
1420}
1421
1422void GrContext::drawVertices(const GrPaint& paint,
1423 GrPrimitiveType primitiveType,
1424 int vertexCount,
1425 const GrPoint positions[],
1426 const GrPoint texCoords[],
1427 const GrColor colors[],
1428 const uint16_t indices[],
1429 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001430 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001431
1432 GrDrawTarget::AutoReleaseGeometry geo;
1433
1434 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1435
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001436 bool hasTexCoords[GrPaint::kTotalStages] = {
1437 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1438 0 // remaining stages use positions
1439 };
1440
1441 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001442
1443 if (NULL != colors) {
1444 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001445 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001446 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001447
1448 if (sizeof(GrPoint) != vertexSize) {
1449 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001450 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001451 return;
1452 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001453 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001454 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001455 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1456 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001457 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001458 NULL,
1459 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460 void* curVertex = geo.vertices();
1461
1462 for (int i = 0; i < vertexCount; ++i) {
1463 *((GrPoint*)curVertex) = positions[i];
1464
1465 if (texOffsets[0] > 0) {
1466 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1467 }
1468 if (colorOffset > 0) {
1469 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1470 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001471 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472 }
1473 } else {
1474 target->setVertexSourceToArray(layout, positions, vertexCount);
1475 }
1476
bsalomon@google.com91958362011-06-13 17:58:13 +00001477 // we don't currently apply offscreen AA to this path. Need improved
1478 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001479
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001480 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001481 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001482 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001483 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001484 target->drawNonIndexed(primitiveType, 0, vertexCount);
1485 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001486}
1487
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001488///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001489
reed@google.com07f3ee12011-05-16 17:21:57 +00001490void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1491 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001492
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001493 if (path.isEmpty()) {
1494#if GR_DEBUG
1495 GrPrintf("Empty path should have been caught by canvas.\n");
1496#endif
1497 if (GrIsFillInverted(fill)) {
1498 this->drawPaint(paint);
1499 }
1500 return;
1501 }
1502
bsalomon@google.com27847de2011-02-22 20:59:41 +00001503 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001504
bsalomon@google.com289533a2011-10-27 12:34:25 +00001505 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1506
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001507 // An Assumption here is that path renderer would use some form of tweaking
1508 // the src color (either the input alpha or in the frag shader) to implement
1509 // aa. If we have some future driver-mojo path AA that can do the right
1510 // thing WRT to the blend then we'll need some query on the PR.
1511 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001512#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001513 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001514#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001515 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001516 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001517
1518 bool doOSAA = false;
1519 GrPathRenderer* pr = NULL;
1520 if (prAA) {
1521 pr = this->getPathRenderer(path, fill, true);
1522 if (NULL == pr) {
1523 prAA = false;
1524 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1525 pr = this->getPathRenderer(path, fill, false);
1526 }
1527 } else {
1528 pr = this->getPathRenderer(path, fill, false);
1529 }
1530
bsalomon@google.com30085192011-08-19 15:42:31 +00001531 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001532#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001533 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001534#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001535 return;
1536 }
1537
bsalomon@google.com289533a2011-10-27 12:34:25 +00001538 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.comee435122011-07-01 14:57:55 +00001539 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001540
bsalomon@google.com289533a2011-10-27 12:34:25 +00001541 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001542 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001543
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001544 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001545 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1546 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001547 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001548 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001549 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001550 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001551 return;
1552 }
1553 }
reed@google.com70c136e2011-06-03 19:51:26 +00001554
reed@google.com07f3ee12011-05-16 17:21:57 +00001555 GrRect pathBounds = path.getBounds();
1556 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001557 if (NULL != translate) {
1558 pathBounds.offset(*translate);
1559 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001560 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001561 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001562 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001563 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001564 return;
1565 }
1566 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001567 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001568 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1569 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001570 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1571 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1572 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001573 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001574 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1575 }
1576 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001577 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001578 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001579 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1580 GrRect rect;
1581 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001582 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1583 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001584 target->drawSimpleRect(rect, NULL, stageMask);
1585 }
1586 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001587 rect.iset(clipIBounds.fLeft, bound.fTop,
1588 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001589 target->drawSimpleRect(rect, NULL, stageMask);
1590 }
1591 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001592 rect.iset(bound.fRight, bound.fTop,
1593 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001594 target->drawSimpleRect(rect, NULL, stageMask);
1595 }
1596 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001597 rect.iset(clipIBounds.fLeft, bound.fBottom,
1598 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001599 target->drawSimpleRect(rect, NULL, stageMask);
1600 }
1601 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001602 return;
1603 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001604 }
1605 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001606}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001607
bsalomon@google.com27847de2011-02-22 20:59:41 +00001608////////////////////////////////////////////////////////////////////////////////
1609
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001610bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001611 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001612}
1613
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001614void GrContext::flush(int flagsBitfield) {
1615 if (kDiscard_FlushBit & flagsBitfield) {
1616 fDrawBuffer->reset();
1617 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001618 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001619 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001620 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001621 fGpu->forceRenderTargetFlush();
1622 }
1623}
1624
1625void GrContext::flushText() {
1626 if (kText_DrawCategory == fLastDrawCategory) {
1627 flushDrawBuffer();
1628 }
1629}
1630
1631void GrContext::flushDrawBuffer() {
1632#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001633 if (fDrawBuffer) {
1634 fDrawBuffer->playback(fGpu);
1635 fDrawBuffer->reset();
1636 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001637#endif
1638}
1639
bsalomon@google.com6f379512011-11-16 20:36:03 +00001640void GrContext::internalWriteTexturePixels(GrTexture* texture,
1641 int left, int top,
1642 int width, int height,
1643 GrPixelConfig config,
1644 const void* buffer,
1645 size_t rowBytes,
1646 uint32_t flags) {
1647 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
1648 if (!(kDontFlush_PixelOpsFlag & flags)) {
1649 this->flush();
1650 }
1651 // TODO: use scratch texture to perform conversion
1652 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1653 GrPixelConfigIsUnpremultiplied(config)) {
1654 return;
1655 }
1656
1657 fGpu->writeTexturePixels(texture, left, top, width, height,
1658 config, buffer, rowBytes);
1659}
1660
1661bool GrContext::internalReadTexturePixels(GrTexture* texture,
1662 int left, int top,
1663 int width, int height,
1664 GrPixelConfig config,
1665 void* buffer,
1666 size_t rowBytes,
1667 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001668 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001669
1670 // TODO: code read pixels for textures that aren't rendertargets
1671
bsalomon@google.com6f379512011-11-16 20:36:03 +00001672 if (!(kDontFlush_PixelOpsFlag & flags)) {
1673 this->flush();
1674 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001675 GrRenderTarget* target = texture->asRenderTarget();
1676 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001677 return this->internalReadRenderTargetPixels(target,
1678 left, top, width, height,
1679 config, buffer, rowBytes,
1680 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001681 } else {
1682 return false;
1683 }
1684}
1685
bsalomon@google.com6f379512011-11-16 20:36:03 +00001686bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1687 int left, int top,
1688 int width, int height,
1689 GrPixelConfig config,
1690 void* buffer,
1691 size_t rowBytes,
1692 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001693 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001694 if (NULL == target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001695 target = fGpu->getRenderTarget();
1696 if (NULL == target) {
1697 return false;
1698 }
1699 }
1700
1701 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1702 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1703 // not supported at this time.
1704 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1705 !GrPixelConfigIsUnpremultiplied(config)) {
1706 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001707 }
1708
bsalomon@google.com6f379512011-11-16 20:36:03 +00001709 if (!(kDontFlush_PixelOpsFlag & flags)) {
1710 this->flush();
1711 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001712
1713 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001714 bool swapRAndB = NULL != src &&
1715 fGpu->preferredReadPixelsConfig(config) ==
1716 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001717
1718 bool flipY = NULL != src &&
1719 fGpu->readPixelsWillPayForYFlip(target, left, top,
1720 width, height, config,
1721 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001722 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1723 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001724
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001725 if (NULL == src && alphaConversion) {
1726 // we should fallback to cpu conversion here. This could happen when
1727 // we were given an external render target by the client that is not
1728 // also a texture (e.g. FBO 0 in GL)
1729 return false;
1730 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001731 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001732 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001733 if (flipY || swapRAndB || alphaConversion) {
1734 GrAssert(NULL != src);
1735 if (swapRAndB) {
1736 config = GrPixelConfigSwapRAndB(config);
1737 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001738 }
1739 // Make the scratch a render target because we don't have a robust
1740 // readTexturePixels as of yet (it calls this function).
1741 const GrTextureDesc desc = {
1742 kRenderTarget_GrTextureFlagBit,
1743 kNone_GrAALevel,
1744 width, height,
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001745 { config }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001746 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001747
1748 ast.set(this, desc);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001749 GrTexture* texture = ast.texture();
1750 if (!texture) {
1751 return false;
1752 }
1753 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001754 GrAssert(NULL != target);
1755
1756 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001757 reset_target_state(fGpu);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001758
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001759 fGpu->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001760
1761 GrSamplerState sampler;
1762 sampler.setClampNoFilter();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001763 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001764 GrMatrix matrix;
1765 if (flipY) {
1766 matrix.setTranslate(SK_Scalar1 * left,
1767 SK_Scalar1 * (top + height));
1768 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1769 } else {
1770 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1771 }
1772 matrix.postIDiv(src->width(), src->height());
1773 sampler.setMatrix(matrix);
1774 fGpu->setSamplerState(0, sampler);
1775 fGpu->setTexture(0, src);
1776 GrRect rect;
1777 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1778 fGpu->drawSimpleRect(rect, NULL, 0x1);
1779 left = 0;
1780 top = 0;
1781 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001782 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001783 left, top, width, height,
1784 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001785}
1786
bsalomon@google.com6f379512011-11-16 20:36:03 +00001787void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1788 int left, int top,
1789 int width, int height,
1790 GrPixelConfig config,
1791 const void* buffer,
1792 size_t rowBytes,
1793 uint32_t flags) {
1794 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
1795
1796 if (NULL == target) {
1797 target = fGpu->getRenderTarget();
1798 if (NULL == target) {
1799 return;
1800 }
1801 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001802
1803 // TODO: when underlying api has a direct way to do this we should use it
1804 // (e.g. glDrawPixels on desktop GL).
1805
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001806 const GrTextureDesc desc = {
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001807 kNone_GrTextureFlags, kNone_GrAALevel, width, height, { config }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001808 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001809 GrAutoScratchTexture ast(this, desc);
1810 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001811 if (NULL == texture) {
1812 return;
1813 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001814 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1815 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001816
bsalomon@google.com27847de2011-02-22 20:59:41 +00001817 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001818 reset_target_state(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001819
1820 GrMatrix matrix;
1821 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1822 fGpu->setViewMatrix(matrix);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001823 fGpu->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001824 fGpu->setTexture(0, texture);
1825
1826 GrSamplerState sampler;
1827 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001828 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001829 sampler.setMatrix(matrix);
1830 fGpu->setSamplerState(0, sampler);
1831
1832 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1833 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001834 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001835 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1836 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001837 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001838 return;
1839 }
1840 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1841 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1842}
1843////////////////////////////////////////////////////////////////////////////////
1844
1845void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001846
1847 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1848 int s = i + GrPaint::kFirstTextureStage;
1849 target->setTexture(s, paint.getTexture(i));
1850 target->setSamplerState(s, *paint.getTextureSampler(i));
1851 }
1852
1853 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1854
1855 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1856 int s = i + GrPaint::kFirstMaskStage;
1857 target->setTexture(s, paint.getMask(i));
1858 target->setSamplerState(s, *paint.getMaskSampler(i));
1859 }
1860
bsalomon@google.com27847de2011-02-22 20:59:41 +00001861 target->setColor(paint.fColor);
1862
1863 if (paint.fDither) {
1864 target->enableState(GrDrawTarget::kDither_StateBit);
1865 } else {
1866 target->disableState(GrDrawTarget::kDither_StateBit);
1867 }
1868 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001869 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001870 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001871 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001872 }
1873 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001874 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001875
1876 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1877 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1878 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001879}
1880
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001881GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001882 DrawCategory category) {
1883 if (category != fLastDrawCategory) {
1884 flushDrawBuffer();
1885 fLastDrawCategory = category;
1886 }
1887 SetPaint(paint, fGpu);
1888 GrDrawTarget* target = fGpu;
1889 switch (category) {
1890 case kText_DrawCategory:
1891#if DEFER_TEXT_RENDERING
1892 target = fDrawBuffer;
1893 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1894#else
1895 target = fGpu;
1896#endif
1897 break;
1898 case kUnbuffered_DrawCategory:
1899 target = fGpu;
1900 break;
1901 case kBuffered_DrawCategory:
1902 target = fDrawBuffer;
1903 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1904 break;
1905 }
1906 return target;
1907}
1908
bsalomon@google.com289533a2011-10-27 12:34:25 +00001909GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1910 GrPathFill fill,
1911 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001912 if (NULL == fPathRendererChain) {
1913 fPathRendererChain =
1914 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1915 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001916 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1917 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001918}
1919
bsalomon@google.com27847de2011-02-22 20:59:41 +00001920////////////////////////////////////////////////////////////////////////////////
1921
bsalomon@google.com27847de2011-02-22 20:59:41 +00001922void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001923 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001924 fGpu->setRenderTarget(target);
1925}
1926
1927GrRenderTarget* GrContext::getRenderTarget() {
1928 return fGpu->getRenderTarget();
1929}
1930
1931const GrRenderTarget* GrContext::getRenderTarget() const {
1932 return fGpu->getRenderTarget();
1933}
1934
1935const GrMatrix& GrContext::getMatrix() const {
1936 return fGpu->getViewMatrix();
1937}
1938
1939void GrContext::setMatrix(const GrMatrix& m) {
1940 fGpu->setViewMatrix(m);
1941}
1942
1943void GrContext::concatMatrix(const GrMatrix& m) const {
1944 fGpu->preConcatViewMatrix(m);
1945}
1946
1947static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1948 intptr_t mask = 1 << shift;
1949 if (pred) {
1950 bits |= mask;
1951 } else {
1952 bits &= ~mask;
1953 }
1954 return bits;
1955}
1956
1957void GrContext::resetStats() {
1958 fGpu->resetStats();
1959}
1960
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001961const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001962 return fGpu->getStats();
1963}
1964
1965void GrContext::printStats() const {
1966 fGpu->printStats();
1967}
1968
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001969GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001970 fGpu = gpu;
1971 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001972 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001973
bsalomon@google.com30085192011-08-19 15:42:31 +00001974 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001975
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001976 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1977 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001978 fFontCache = new GrFontCache(fGpu);
1979
1980 fLastDrawCategory = kUnbuffered_DrawCategory;
1981
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001982 fDrawBuffer = NULL;
1983 fDrawBufferVBAllocPool = NULL;
1984 fDrawBufferIBAllocPool = NULL;
1985
bsalomon@google.com205d4602011-04-25 12:43:45 +00001986 fAAFillRectIndexBuffer = NULL;
1987 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001988
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001989 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1990 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001991 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1992 }
1993 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001994
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001995 this->setupDrawBuffer();
1996}
1997
1998void GrContext::setupDrawBuffer() {
1999
2000 GrAssert(NULL == fDrawBuffer);
2001 GrAssert(NULL == fDrawBufferVBAllocPool);
2002 GrAssert(NULL == fDrawBufferIBAllocPool);
2003
bsalomon@google.com27847de2011-02-22 20:59:41 +00002004#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002005 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002006 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002007 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2008 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002009 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002010 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002011 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002012 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2013
bsalomon@google.com471d4712011-08-23 15:45:25 +00002014 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2015 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002016 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002017#endif
2018
2019#if BATCH_RECT_TO_RECT
2020 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2021#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002022}
2023
bsalomon@google.com27847de2011-02-22 20:59:41 +00002024GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2025 GrDrawTarget* target;
2026#if DEFER_TEXT_RENDERING
2027 target = prepareToDraw(paint, kText_DrawCategory);
2028#else
2029 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2030#endif
2031 SetPaint(paint, target);
2032 return target;
2033}
2034
2035const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2036 return fGpu->getQuadIndexBuffer();
2037}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002038
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002039void GrContext::convolveInX(GrTexture* texture,
2040 const SkRect& rect,
2041 const float* kernel,
2042 int kernelWidth) {
bsalomon@google.com99621082011-11-15 16:47:16 +00002043 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002044 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2045}
2046
2047void GrContext::convolveInY(GrTexture* texture,
2048 const SkRect& rect,
2049 const float* kernel,
2050 int kernelWidth) {
bsalomon@google.com99621082011-11-15 16:47:16 +00002051 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002052 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2053}
2054
2055void GrContext::convolve(GrTexture* texture,
2056 const SkRect& rect,
2057 float imageIncrement[2],
2058 const float* kernel,
2059 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002060 GrDrawTarget::AutoStateRestore asr(fGpu);
2061 GrMatrix sampleM;
2062 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
2063 GrSamplerState::kClamp_WrapMode,
2064 GrSamplerState::kConvolution_Filter);
2065 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002066 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002067 sampler.setMatrix(sampleM);
2068 fGpu->setSamplerState(0, sampler);
2069 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002070 fGpu->setTexture(0, texture);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002071 fGpu->setColor(0xFFFFFFFF);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002072 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002073 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2074}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002075
2076///////////////////////////////////////////////////////////////////////////////