blob: 3a26d2f609b0e8d04c2c51a030b948814c7cbb7e [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.com598a1ff2011-11-18 18:15:42 +00001806 // If the RT is also a texture and we don't have to do PM/UPM conversion
1807 // then take the texture path, which we expect to be at least as fast or
1808 // faster since it doesn't use an intermediate texture as we do below.
1809 if (NULL != target->asTexture() &&
1810 GrPixelConfigIsUnpremultiplied(target->config()) ==
1811 GrPixelConfigIsUnpremultiplied(config)) {
1812
1813 this->internalWriteTexturePixels(target->asTexture(),
1814 left, top, width, height,
1815 config, buffer, rowBytes, flags);
1816 return;
1817 }
1818
1819 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1820 GrPixelConfigSwapRAndB(config);
1821 if (swapRAndB) {
1822 config = GrPixelConfigSwapRAndB(config);
1823 }
1824
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001825 const GrTextureDesc desc = {
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001826 kNone_GrTextureFlags, kNone_GrAALevel, width, height, { config }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001827 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001828 GrAutoScratchTexture ast(this, desc);
1829 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001830 if (NULL == texture) {
1831 return;
1832 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001833 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1834 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001835
bsalomon@google.com27847de2011-02-22 20:59:41 +00001836 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001837 reset_target_state(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001838
1839 GrMatrix matrix;
1840 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1841 fGpu->setViewMatrix(matrix);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001842 fGpu->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001843 fGpu->setTexture(0, texture);
1844
1845 GrSamplerState sampler;
1846 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001847 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001848 sampler.setMatrix(matrix);
bsalomon@google.com598a1ff2011-11-18 18:15:42 +00001849 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001850 fGpu->setSamplerState(0, sampler);
1851
1852 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1853 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001854 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001855 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1856 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001857 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001858 return;
1859 }
1860 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1861 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1862}
1863////////////////////////////////////////////////////////////////////////////////
1864
1865void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001866
1867 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1868 int s = i + GrPaint::kFirstTextureStage;
1869 target->setTexture(s, paint.getTexture(i));
1870 target->setSamplerState(s, *paint.getTextureSampler(i));
1871 }
1872
1873 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1874
1875 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1876 int s = i + GrPaint::kFirstMaskStage;
1877 target->setTexture(s, paint.getMask(i));
1878 target->setSamplerState(s, *paint.getMaskSampler(i));
1879 }
1880
bsalomon@google.com27847de2011-02-22 20:59:41 +00001881 target->setColor(paint.fColor);
1882
1883 if (paint.fDither) {
1884 target->enableState(GrDrawTarget::kDither_StateBit);
1885 } else {
1886 target->disableState(GrDrawTarget::kDither_StateBit);
1887 }
1888 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001889 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001890 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001891 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001892 }
1893 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001894 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001895
1896 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1897 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1898 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001899}
1900
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001901GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001902 DrawCategory category) {
1903 if (category != fLastDrawCategory) {
1904 flushDrawBuffer();
1905 fLastDrawCategory = category;
1906 }
1907 SetPaint(paint, fGpu);
1908 GrDrawTarget* target = fGpu;
1909 switch (category) {
1910 case kText_DrawCategory:
1911#if DEFER_TEXT_RENDERING
1912 target = fDrawBuffer;
1913 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1914#else
1915 target = fGpu;
1916#endif
1917 break;
1918 case kUnbuffered_DrawCategory:
1919 target = fGpu;
1920 break;
1921 case kBuffered_DrawCategory:
1922 target = fDrawBuffer;
1923 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1924 break;
1925 }
1926 return target;
1927}
1928
bsalomon@google.com289533a2011-10-27 12:34:25 +00001929GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1930 GrPathFill fill,
1931 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001932 if (NULL == fPathRendererChain) {
1933 fPathRendererChain =
1934 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1935 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001936 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1937 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001938}
1939
bsalomon@google.com27847de2011-02-22 20:59:41 +00001940////////////////////////////////////////////////////////////////////////////////
1941
bsalomon@google.com27847de2011-02-22 20:59:41 +00001942void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001943 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001944 fGpu->setRenderTarget(target);
1945}
1946
1947GrRenderTarget* GrContext::getRenderTarget() {
1948 return fGpu->getRenderTarget();
1949}
1950
1951const GrRenderTarget* GrContext::getRenderTarget() const {
1952 return fGpu->getRenderTarget();
1953}
1954
1955const GrMatrix& GrContext::getMatrix() const {
1956 return fGpu->getViewMatrix();
1957}
1958
1959void GrContext::setMatrix(const GrMatrix& m) {
1960 fGpu->setViewMatrix(m);
1961}
1962
1963void GrContext::concatMatrix(const GrMatrix& m) const {
1964 fGpu->preConcatViewMatrix(m);
1965}
1966
1967static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1968 intptr_t mask = 1 << shift;
1969 if (pred) {
1970 bits |= mask;
1971 } else {
1972 bits &= ~mask;
1973 }
1974 return bits;
1975}
1976
1977void GrContext::resetStats() {
1978 fGpu->resetStats();
1979}
1980
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001981const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982 return fGpu->getStats();
1983}
1984
1985void GrContext::printStats() const {
1986 fGpu->printStats();
1987}
1988
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001989GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001990 fGpu = gpu;
1991 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001992 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001993
bsalomon@google.com30085192011-08-19 15:42:31 +00001994 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001995
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001996 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1997 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001998 fFontCache = new GrFontCache(fGpu);
1999
2000 fLastDrawCategory = kUnbuffered_DrawCategory;
2001
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002002 fDrawBuffer = NULL;
2003 fDrawBufferVBAllocPool = NULL;
2004 fDrawBufferIBAllocPool = NULL;
2005
bsalomon@google.com205d4602011-04-25 12:43:45 +00002006 fAAFillRectIndexBuffer = NULL;
2007 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002008
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002009 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2010 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002011 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2012 }
2013 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002014
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002015 this->setupDrawBuffer();
2016}
2017
2018void GrContext::setupDrawBuffer() {
2019
2020 GrAssert(NULL == fDrawBuffer);
2021 GrAssert(NULL == fDrawBufferVBAllocPool);
2022 GrAssert(NULL == fDrawBufferIBAllocPool);
2023
bsalomon@google.com27847de2011-02-22 20:59:41 +00002024#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002025 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002026 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002027 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2028 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002029 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002030 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002031 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002032 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2033
bsalomon@google.com471d4712011-08-23 15:45:25 +00002034 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2035 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002036 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002037#endif
2038
2039#if BATCH_RECT_TO_RECT
2040 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2041#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002042}
2043
bsalomon@google.com27847de2011-02-22 20:59:41 +00002044GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2045 GrDrawTarget* target;
2046#if DEFER_TEXT_RENDERING
2047 target = prepareToDraw(paint, kText_DrawCategory);
2048#else
2049 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2050#endif
2051 SetPaint(paint, target);
2052 return target;
2053}
2054
2055const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2056 return fGpu->getQuadIndexBuffer();
2057}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002058
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002059void GrContext::convolveInX(GrTexture* texture,
2060 const SkRect& rect,
2061 const float* kernel,
2062 int kernelWidth) {
bsalomon@google.com99621082011-11-15 16:47:16 +00002063 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002064 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2065}
2066
2067void GrContext::convolveInY(GrTexture* texture,
2068 const SkRect& rect,
2069 const float* kernel,
2070 int kernelWidth) {
bsalomon@google.com99621082011-11-15 16:47:16 +00002071 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002072 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2073}
2074
2075void GrContext::convolve(GrTexture* texture,
2076 const SkRect& rect,
2077 float imageIncrement[2],
2078 const float* kernel,
2079 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002080 GrDrawTarget::AutoStateRestore asr(fGpu);
2081 GrMatrix sampleM;
2082 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
2083 GrSamplerState::kClamp_WrapMode,
2084 GrSamplerState::kConvolution_Filter);
2085 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002086 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002087 sampler.setMatrix(sampleM);
2088 fGpu->setSamplerState(0, sampler);
2089 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002090 fGpu->setTexture(0, texture);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002091 fGpu->setColor(0xFFFFFFFF);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002092 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002093 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2094}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002095
2096///////////////////////////////////////////////////////////////////////////////