blob: ca01192b772f14d1a865500e095f25bf8e5c3ee0 [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.com18c9c192011-09-22 21:01:31 +0000334 rtDesc.fWidth =
335 GrNextPow2(GrMax<int>(desc.fWidth,
336 fGpu->getCaps().fMinRenderTargetWidth));
337 rtDesc.fHeight =
338 GrNextPow2(GrMax<int>(desc.fHeight,
339 fGpu->getCaps().fMinRenderTargetHeight));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000340
341 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
342
343 if (NULL != texture) {
344 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000345 reset_target_state(fGpu);
346
bsalomon@google.com27847de2011-02-22 20:59:41 +0000347 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000348 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000349
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000350 GrSamplerState::Filter filter;
351 // if filtering is not desired then we want to ensure all
352 // texels in the resampled image are copies of texels from
353 // the original.
354 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
355 filter = GrSamplerState::kNearest_Filter;
356 } else {
357 filter = GrSamplerState::kBilinear_Filter;
358 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000359 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
360 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000361 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000362 fGpu->setSamplerState(0, stretchSampler);
363
364 static const GrVertexLayout layout =
365 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
366 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
367
368 if (arg.succeeded()) {
369 GrPoint* verts = (GrPoint*) arg.vertices();
370 verts[0].setIRectFan(0, 0,
371 texture->width(),
372 texture->height(),
373 2*sizeof(GrPoint));
374 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
375 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
376 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000377 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000378 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000379 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000380 } else {
381 // TODO: Our CPU stretch doesn't filter. But we create separate
382 // stretched textures when the sampler state is either filtered or
383 // not. Either implement filtered stretch blit on CPU or just create
384 // one when FBO case fails.
385
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000386 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000387 // no longer need to clamp at min RT size.
388 rtDesc.fWidth = GrNextPow2(desc.fWidth);
389 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000390 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000391 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000392 rtDesc.fWidth *
393 rtDesc.fHeight);
394 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
395 srcData, desc.fWidth, desc.fHeight, bpp);
396
397 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
398
399 GrTexture* texture = fGpu->createTexture(rtDesc,
400 stretchedPixels.get(),
401 stretchedRowBytes);
402 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000404 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000405 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000406
407 } else {
408 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
409 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000410 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000411 }
412 }
413 return entry;
414}
415
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416namespace {
417inline void gen_scratch_tex_key_values(const GrGpu* gpu,
418 const GrTextureDesc& desc,
419 uint32_t v[4]) {
420 // Instead of a client-provided key of the texture contents
421 // we create a key of from the descriptor.
422 GrContext::TextureKey descKey = desc.fAALevel |
423 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000424 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000425 // this code path isn't friendly to tiling with NPOT restricitons
426 // We just pass ClampNoFilter()
427 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
428 desc.fWidth, desc.fHeight, true, v);
429}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000430}
431
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000432GrContext::TextureCacheEntry GrContext::lockScratchTexture(
433 const GrTextureDesc& inDesc,
434 ScratchTexMatch match) {
435
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000436 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000437 if (kExact_ScratchTexMatch != match) {
438 // bin by pow2 with a reasonable min
439 static const int MIN_SIZE = 256;
440 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
441 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
442 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000443
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000444 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000445 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
446
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000447 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000448 int origWidth = desc.fWidth;
449 int origHeight = desc.fHeight;
450 bool doubledW = false;
451 bool doubledH = false;
452
453 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000454 uint32_t v[4];
455 gen_scratch_tex_key_values(fGpu, desc, v);
456 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000457 entry = fTextureCache->findAndLock(key,
458 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000459 // if we miss, relax the fit of the flags...
460 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000461 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000462 break;
463 }
464 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
465 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
466 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
467 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
468 } else if (!doubledW) {
469 desc.fFlags = inDesc.fFlags;
470 desc.fWidth *= 2;
471 doubledW = true;
472 } else if (!doubledH) {
473 desc.fFlags = inDesc.fFlags;
474 desc.fWidth = origWidth;
475 desc.fHeight *= 2;
476 doubledH = true;
477 } else {
478 break;
479 }
480
481 } while (true);
482
483 if (NULL == entry) {
484 desc.fFlags = inDesc.fFlags;
485 desc.fWidth = origWidth;
486 desc.fHeight = origHeight;
487 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
488 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000489 uint32_t v[4];
490 gen_scratch_tex_key_values(fGpu, desc, v);
491 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000492 entry = fTextureCache->createAndLock(key, texture);
493 }
494 }
495
496 // If the caller gives us the same desc/sampler twice we don't want
497 // to return the same texture the second time (unless it was previously
498 // released). So we detach the entry from the cache and reattach at release.
499 if (NULL != entry) {
500 fTextureCache->detach(entry);
501 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000502 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000503}
504
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000505void GrContext::unlockTexture(TextureCacheEntry entry) {
506 // If this is a scratch texture we detached it from the cache
507 // while it was locked (to avoid two callers simultaneously getting
508 // the same texture).
509 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
510 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000511 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000512 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000513 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000514}
515
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000516GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000517 void* srcData,
518 size_t rowBytes) {
519 return fGpu->createTexture(desc, srcData, rowBytes);
520}
521
522void GrContext::getTextureCacheLimits(int* maxTextures,
523 size_t* maxTextureBytes) const {
524 fTextureCache->getLimits(maxTextures, maxTextureBytes);
525}
526
527void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
528 fTextureCache->setLimits(maxTextures, maxTextureBytes);
529}
530
bsalomon@google.com91958362011-06-13 17:58:13 +0000531int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000532 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000533}
534
535int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000536 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000537}
538
539///////////////////////////////////////////////////////////////////////////////
540
bsalomon@google.come269f212011-11-07 13:29:52 +0000541GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
542 return fGpu->createPlatformTexture(desc);
543}
544
545GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
546 return fGpu->createPlatformRenderTarget(desc);
547}
548
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000549GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
550 // validate flags here so that GrGpu subclasses don't have to check
551 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
552 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000553 return NULL;
554 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000555 if (desc.fSampleCnt &&
556 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000557 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000558 }
559 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
560 desc.fSampleCnt &&
561 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
562 return NULL;
563 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000564 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000565}
566
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000567///////////////////////////////////////////////////////////////////////////////
568
bsalomon@google.com27847de2011-02-22 20:59:41 +0000569bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000570 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000571 const GrDrawTarget::Caps& caps = fGpu->getCaps();
572 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000573 return false;
574 }
575
bsalomon@google.com27847de2011-02-22 20:59:41 +0000576 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
577
578 if (!isPow2) {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000579 if (!caps.fNPOTTextureSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000580 return false;
581 }
582
583 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
584 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000585 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000586 return false;
587 }
588 }
589 return true;
590}
591
592////////////////////////////////////////////////////////////////////////////////
593
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000594const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
595
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596void GrContext::setClip(const GrClip& clip) {
597 fGpu->setClip(clip);
598 fGpu->enableState(GrDrawTarget::kClip_StateBit);
599}
600
601void GrContext::setClip(const GrIRect& rect) {
602 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000603 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000604 fGpu->setClip(clip);
605}
606
607////////////////////////////////////////////////////////////////////////////////
608
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000609void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000610 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000611 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000612}
613
614void GrContext::drawPaint(const GrPaint& paint) {
615 // set rect to be big enough to fill the space, but not super-huge, so we
616 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000617 GrRect r;
618 r.setLTRB(0, 0,
619 GrIntToScalar(getRenderTarget()->width()),
620 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000621 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000622 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000623 SkTLazy<GrPaint> tmpPaint;
624 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000625 // We attempt to map r by the inverse matrix and draw that. mapRect will
626 // map the four corners and bound them with a new rect. This will not
627 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000628 if (!this->getMatrix().hasPerspective()) {
629 if (!fGpu->getViewInverse(&inverse)) {
630 GrPrintf("Could not invert matrix");
631 return;
632 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000633 inverse.mapRect(&r);
634 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000635 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
636 if (!fGpu->getViewInverse(&inverse)) {
637 GrPrintf("Could not invert matrix");
638 return;
639 }
640 tmpPaint.set(paint);
641 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
642 p = tmpPaint.get();
643 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000644 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000645 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000646 // by definition this fills the entire clip, no need for AA
647 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000648 if (!tmpPaint.isValid()) {
649 tmpPaint.set(paint);
650 p = tmpPaint.get();
651 }
652 GrAssert(p == tmpPaint.get());
653 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000654 }
655 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656}
657
bsalomon@google.com205d4602011-04-25 12:43:45 +0000658////////////////////////////////////////////////////////////////////////////////
659
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000660namespace {
661inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
662 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
663}
664}
665
bsalomon@google.com91958362011-06-13 17:58:13 +0000666struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000667 enum Downsample {
668 k4x4TwoPass_Downsample,
669 k4x4SinglePass_Downsample,
670 kFSAA_Downsample
671 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000672 int fTileSizeX;
673 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000674 int fTileCountX;
675 int fTileCountY;
676 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000677 GrAutoScratchTexture fOffscreen0;
678 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000679 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000680 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000681};
682
bsalomon@google.com471d4712011-08-23 15:45:25 +0000683bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000684 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000685#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000686 return false;
687#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000688 // Line primitves are always rasterized as 1 pixel wide.
689 // Super-sampling would make them too thin but MSAA would be OK.
690 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000691 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000692 return false;
693 }
694 if (target->getRenderTarget()->isMultisampled()) {
695 return false;
696 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000697 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000698#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000699 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000700#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000701 return false;
702 }
703 return true;
704#endif
705}
706
bsalomon@google.com91958362011-06-13 17:58:13 +0000707bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000708 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000709 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000710 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000711 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000712
713 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000714
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000715 GrAssert(NULL == record->fOffscreen0.texture());
716 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000717 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000718
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000719 int boundW = boundRect.width();
720 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000721
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000722 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000723
724 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
725 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
726
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000727 if (requireStencil) {
728 desc.fFlags = kRenderTarget_GrTextureFlagBit;
729 } else {
730 desc.fFlags = kRenderTarget_GrTextureFlagBit |
731 kNoStencil_GrTextureFlagBit;
732 }
733
bsalomon@google.comc4364992011-11-07 15:54:49 +0000734 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000735
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000736 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000737 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000738 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000739 desc.fAALevel = kMed_GrAALevel;
740 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000741 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000742 OffscreenRecord::k4x4SinglePass_Downsample :
743 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000744 record->fScale = OFFSCREEN_SSAA_SCALE;
745 // both downsample paths assume this
746 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000747 desc.fAALevel = kNone_GrAALevel;
748 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000749
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000750 desc.fWidth *= record->fScale;
751 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000752 record->fOffscreen0.set(this, desc);
753 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000754 return false;
755 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000756 // the approximate lookup might have given us some slop space, might as well
757 // use it when computing the tiles size.
758 // these are scale values, will adjust after considering
759 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000760 record->fTileSizeX = record->fOffscreen0.texture()->width();
761 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000762
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000763 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000764 desc.fWidth /= 2;
765 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000766 record->fOffscreen1.set(this, desc);
767 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768 return false;
769 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000770 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000771 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000772 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000773 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000774 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000775 record->fTileSizeX /= record->fScale;
776 record->fTileSizeY /= record->fScale;
777
778 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
779 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
780
tomhudson@google.com237a4612011-07-19 15:44:00 +0000781 record->fClip = target->getClip();
782
bsalomon@google.com91958362011-06-13 17:58:13 +0000783 target->saveCurrentDrawState(&record->fSavedState);
784 return true;
785}
786
787void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
788 const GrIRect& boundRect,
789 int tileX, int tileY,
790 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000791
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000792 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000793 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000794
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000795 GrPaint tempPaint;
796 tempPaint.reset();
797 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000798 target->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000799#if PREFER_MSAA_OFFSCREEN_AA
800 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
801#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000802
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000803 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000804 int left = boundRect.fLeft + tileX * record->fTileSizeX;
805 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000806 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000807 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000808 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000809 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000810 target->postConcatViewMatrix(scaleM);
811
bsalomon@google.com91958362011-06-13 17:58:13 +0000812 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000813 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000814 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000815 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000816 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
817 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000818 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000819#if 0
820 // visualize tile boundaries by setting edges of offscreen to white
821 // and interior to tranparent. black.
822 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000823
bsalomon@google.com91958362011-06-13 17:58:13 +0000824 static const int gOffset = 2;
825 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
826 record->fScale * w - gOffset,
827 record->fScale * h - gOffset);
828 target->clear(&clear2, 0x0);
829#else
830 target->clear(&clear, 0x0);
831#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000832}
833
bsalomon@google.com91958362011-06-13 17:58:13 +0000834void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000835 const GrPaint& paint,
836 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000837 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000838 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000839 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000840 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000841 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000842 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000843 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
844 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000845 tileRect.fRight = (tileX == record->fTileCountX-1) ?
846 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000847 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000848 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
849 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000850 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000851
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000852 GrSamplerState::Filter filter;
853 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
854 filter = GrSamplerState::k4x4Downsample_Filter;
855 } else {
856 filter = GrSamplerState::kBilinear_Filter;
857 }
858
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000859 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000860 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000861 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000862
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000863 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 int scale;
865
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000866 enum {
867 kOffscreenStage = GrPaint::kTotalStages,
868 };
869
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000870 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000871 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000873 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000874
875 // Do 2x2 downsample from first to second
876 target->setTexture(kOffscreenStage, src);
877 target->setRenderTarget(dst);
878 target->setViewMatrix(GrMatrix::I());
879 sampleM.setScale(scale * GR_Scalar1 / src->width(),
880 scale * GR_Scalar1 / src->height());
881 sampler.setMatrix(sampleM);
882 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000883 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
884 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000885 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
886
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000887 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000888 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000889 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000890 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000891 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000892 } else {
893 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
894 record->fDownsample);
895 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000896 }
897
bsalomon@google.com91958362011-06-13 17:58:13 +0000898 // setup for draw back to main RT, we use the original
899 // draw state setup by the caller plus an additional coverage
900 // stage to handle the AA resolve. Also, we use an identity
901 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000902 int stageMask = paint.getActiveStageMask();
903
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000904 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000905 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000906
907 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000908 GrMatrix invVM;
909 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000910 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000911 }
912 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000913 // This is important when tiling, otherwise second tile's
914 // pass 1 view matrix will be incorrect.
915 GrDrawTarget::AutoViewMatrixRestore avmr(target);
916
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000917 target->setViewMatrix(GrMatrix::I());
918
919 target->setTexture(kOffscreenStage, src);
920 sampleM.setScale(scale * GR_Scalar1 / src->width(),
921 scale * GR_Scalar1 / src->height());
922 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000923 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
924 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000925 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000926 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000927
reed@google.com20efde72011-05-09 17:00:02 +0000928 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000929 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000930 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000931 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000932}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000933
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000934void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
935 GrPathRenderer* pr,
936 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000937 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000938}
939
940////////////////////////////////////////////////////////////////////////////////
941
bsalomon@google.com27847de2011-02-22 20:59:41 +0000942/* create a triangle strip that strokes the specified triangle. There are 8
943 unique vertices, but we repreat the last 2 to close up. Alternatively we
944 could use an indices array, and then only send 8 verts, but not sure that
945 would be faster.
946 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000947static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000948 GrScalar width) {
949 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000950 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000951
952 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
953 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
954 verts[2].set(rect.fRight - rad, rect.fTop + rad);
955 verts[3].set(rect.fRight + rad, rect.fTop - rad);
956 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
957 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
958 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
959 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
960 verts[8] = verts[0];
961 verts[9] = verts[1];
962}
963
bsalomon@google.com205d4602011-04-25 12:43:45 +0000964static void setInsetFan(GrPoint* pts, size_t stride,
965 const GrRect& r, GrScalar dx, GrScalar dy) {
966 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
967}
968
969static const uint16_t gFillAARectIdx[] = {
970 0, 1, 5, 5, 4, 0,
971 1, 2, 6, 6, 5, 1,
972 2, 3, 7, 7, 6, 2,
973 3, 0, 4, 4, 7, 3,
974 4, 5, 6, 6, 7, 4,
975};
976
977int GrContext::aaFillRectIndexCount() const {
978 return GR_ARRAY_COUNT(gFillAARectIdx);
979}
980
981GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
982 if (NULL == fAAFillRectIndexBuffer) {
983 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
984 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000985 if (NULL != fAAFillRectIndexBuffer) {
986 #if GR_DEBUG
987 bool updated =
988 #endif
989 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
990 sizeof(gFillAARectIdx));
991 GR_DEBUGASSERT(updated);
992 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000993 }
994 return fAAFillRectIndexBuffer;
995}
996
997static const uint16_t gStrokeAARectIdx[] = {
998 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
999 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1000 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1001 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1002
1003 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1004 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1005 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1006 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1007
1008 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1009 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1010 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1011 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1012};
1013
1014int GrContext::aaStrokeRectIndexCount() const {
1015 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1016}
1017
1018GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1019 if (NULL == fAAStrokeRectIndexBuffer) {
1020 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1021 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001022 if (NULL != fAAStrokeRectIndexBuffer) {
1023 #if GR_DEBUG
1024 bool updated =
1025 #endif
1026 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1027 sizeof(gStrokeAARectIdx));
1028 GR_DEBUGASSERT(updated);
1029 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001030 }
1031 return fAAStrokeRectIndexBuffer;
1032}
1033
bsalomon@google.coma3108262011-10-10 14:08:47 +00001034static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1035 bool useCoverage) {
1036 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001037 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001038 if (NULL != target->getTexture(s)) {
1039 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1040 }
1041 }
1042 if (useCoverage) {
1043 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1044 } else {
1045 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1046 }
1047 return layout;
1048}
1049
bsalomon@google.com205d4602011-04-25 12:43:45 +00001050void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001051 const GrRect& devRect,
1052 bool useVertexCoverage) {
1053 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001054
1055 size_t vsize = GrDrawTarget::VertexSize(layout);
1056
1057 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001058 if (!geo.succeeded()) {
1059 GrPrintf("Failed to get space for vertices!\n");
1060 return;
1061 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001062 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1063 if (NULL == indexBuffer) {
1064 GrPrintf("Failed to create index buffer!\n");
1065 return;
1066 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001067
1068 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1069
1070 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1071 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1072
1073 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1074 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1075
1076 verts += sizeof(GrPoint);
1077 for (int i = 0; i < 4; ++i) {
1078 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1079 }
1080
bsalomon@google.coma3108262011-10-10 14:08:47 +00001081 GrColor innerColor;
1082 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001083 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001084 } else {
1085 innerColor = target->getColor();
1086 }
1087
bsalomon@google.com205d4602011-04-25 12:43:45 +00001088 verts += 4 * vsize;
1089 for (int i = 0; i < 4; ++i) {
1090 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1091 }
1092
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001093 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001094
1095 target->drawIndexed(kTriangles_PrimitiveType, 0,
1096 0, 8, this->aaFillRectIndexCount());
1097}
1098
bsalomon@google.coma3108262011-10-10 14:08:47 +00001099void GrContext::strokeAARect(GrDrawTarget* target,
1100 const GrRect& devRect,
1101 const GrVec& devStrokeSize,
1102 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001103 const GrScalar& dx = devStrokeSize.fX;
1104 const GrScalar& dy = devStrokeSize.fY;
1105 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1106 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1107
bsalomon@google.com205d4602011-04-25 12:43:45 +00001108 GrScalar spare;
1109 {
1110 GrScalar w = devRect.width() - dx;
1111 GrScalar h = devRect.height() - dy;
1112 spare = GrMin(w, h);
1113 }
1114
1115 if (spare <= 0) {
1116 GrRect r(devRect);
1117 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001118 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001119 return;
1120 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001121 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001122 size_t vsize = GrDrawTarget::VertexSize(layout);
1123
1124 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001125 if (!geo.succeeded()) {
1126 GrPrintf("Failed to get space for vertices!\n");
1127 return;
1128 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001129 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1130 if (NULL == indexBuffer) {
1131 GrPrintf("Failed to create index buffer!\n");
1132 return;
1133 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001134
1135 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1136
1137 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1138 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1139 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1140 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1141
1142 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1143 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1144 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1145 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1146
1147 verts += sizeof(GrPoint);
1148 for (int i = 0; i < 4; ++i) {
1149 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1150 }
1151
bsalomon@google.coma3108262011-10-10 14:08:47 +00001152 GrColor innerColor;
1153 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001154 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001155 } else {
1156 innerColor = target->getColor();
1157 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001158 verts += 4 * vsize;
1159 for (int i = 0; i < 8; ++i) {
1160 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1161 }
1162
1163 verts += 8 * vsize;
1164 for (int i = 0; i < 8; ++i) {
1165 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1166 }
1167
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001168 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001169 target->drawIndexed(kTriangles_PrimitiveType,
1170 0, 0, 16, aaStrokeRectIndexCount());
1171}
1172
reed@google.com20efde72011-05-09 17:00:02 +00001173/**
1174 * Returns true if the rects edges are integer-aligned.
1175 */
1176static bool isIRect(const GrRect& r) {
1177 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1178 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1179}
1180
bsalomon@google.com205d4602011-04-25 12:43:45 +00001181static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001182 const GrRect& rect,
1183 GrScalar width,
1184 const GrMatrix* matrix,
1185 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001186 GrRect* devRect,
1187 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001188 // we use a simple alpha ramp to do aa on axis-aligned rects
1189 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001190 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001191
bsalomon@google.coma3108262011-10-10 14:08:47 +00001192 // we are keeping around the "tweak the alpha" trick because
1193 // it is our only hope for the fixed-pipe implementation.
1194 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001195 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001196 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001197 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001198 if (target->getCaps().fSupportPerVertexCoverage) {
1199 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001200#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001201 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001202#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001203 return false;
1204 } else {
1205 *useVertexCoverage = true;
1206 }
1207 } else {
1208 GrPrintf("Rect AA dropped because no support for coverage.\n");
1209 return false;
1210 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001211 }
1212
1213 if (target->getRenderTarget()->isMultisampled()) {
1214 return false;
1215 }
1216
bsalomon@google.com471d4712011-08-23 15:45:25 +00001217 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001218 return false;
1219 }
1220
1221 if (!target->getViewMatrix().preservesAxisAlignment()) {
1222 return false;
1223 }
1224
1225 if (NULL != matrix &&
1226 !matrix->preservesAxisAlignment()) {
1227 return false;
1228 }
1229
1230 *combinedMatrix = target->getViewMatrix();
1231 if (NULL != matrix) {
1232 combinedMatrix->preConcat(*matrix);
1233 GrAssert(combinedMatrix->preservesAxisAlignment());
1234 }
1235
1236 combinedMatrix->mapRect(devRect, rect);
1237 devRect->sort();
1238
1239 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001240 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001241 } else {
1242 return true;
1243 }
1244}
1245
bsalomon@google.com27847de2011-02-22 20:59:41 +00001246void GrContext::drawRect(const GrPaint& paint,
1247 const GrRect& rect,
1248 GrScalar width,
1249 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001250 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001251
1252 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001253 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001254
bsalomon@google.com205d4602011-04-25 12:43:45 +00001255 GrRect devRect = rect;
1256 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001257 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001258 bool needAA = paint.fAntiAlias &&
1259 !this->getRenderTarget()->isMultisampled();
1260 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1261 &combinedMatrix, &devRect,
1262 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001263
1264 if (doAA) {
1265 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001266 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001267 GrMatrix inv;
1268 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001269 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001270 }
1271 }
1272 target->setViewMatrix(GrMatrix::I());
1273 if (width >= 0) {
1274 GrVec strokeSize;;
1275 if (width > 0) {
1276 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001277 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001278 strokeSize.setAbs(strokeSize);
1279 } else {
1280 strokeSize.set(GR_Scalar1, GR_Scalar1);
1281 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001282 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001283 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001284 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001285 }
1286 return;
1287 }
1288
bsalomon@google.com27847de2011-02-22 20:59:41 +00001289 if (width >= 0) {
1290 // TODO: consider making static vertex buffers for these cases.
1291 // Hairline could be done by just adding closing vertex to
1292 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001293 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1294
bsalomon@google.com27847de2011-02-22 20:59:41 +00001295 static const int worstCaseVertCount = 10;
1296 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1297
1298 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001299 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300 return;
1301 }
1302
1303 GrPrimitiveType primType;
1304 int vertCount;
1305 GrPoint* vertex = geo.positions();
1306
1307 if (width > 0) {
1308 vertCount = 10;
1309 primType = kTriangleStrip_PrimitiveType;
1310 setStrokeRectStrip(vertex, rect, width);
1311 } else {
1312 // hairline
1313 vertCount = 5;
1314 primType = kLineStrip_PrimitiveType;
1315 vertex[0].set(rect.fLeft, rect.fTop);
1316 vertex[1].set(rect.fRight, rect.fTop);
1317 vertex[2].set(rect.fRight, rect.fBottom);
1318 vertex[3].set(rect.fLeft, rect.fBottom);
1319 vertex[4].set(rect.fLeft, rect.fTop);
1320 }
1321
1322 GrDrawTarget::AutoViewMatrixRestore avmr;
1323 if (NULL != matrix) {
1324 avmr.set(target);
1325 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001326 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327 }
1328
1329 target->drawNonIndexed(primType, 0, vertCount);
1330 } else {
1331 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001332 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001333 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1334 if (NULL == sqVB) {
1335 GrPrintf("Failed to create static rect vb.\n");
1336 return;
1337 }
1338 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001339 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1340 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001341 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001342 0, rect.height(), rect.fTop,
1343 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344
1345 if (NULL != matrix) {
1346 m.postConcat(*matrix);
1347 }
1348
1349 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001350 target->preConcatSamplerMatrices(stageMask, m);
1351
bsalomon@google.com27847de2011-02-22 20:59:41 +00001352 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1353 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001354 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001355 #endif
1356 }
1357}
1358
1359void GrContext::drawRectToRect(const GrPaint& paint,
1360 const GrRect& dstRect,
1361 const GrRect& srcRect,
1362 const GrMatrix* dstMatrix,
1363 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001364 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001365
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001366 // srcRect refers to paint's first texture
1367 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001368 drawRect(paint, dstRect, -1, dstMatrix);
1369 return;
1370 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001371
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1373
1374#if GR_STATIC_RECT_VB
1375 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001376
1377 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001378 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1379
1380 GrMatrix m;
1381
1382 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1383 0, dstRect.height(), dstRect.fTop,
1384 0, 0, GrMatrix::I()[8]);
1385 if (NULL != dstMatrix) {
1386 m.postConcat(*dstMatrix);
1387 }
1388 target->preConcatViewMatrix(m);
1389
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001390 // srcRect refers to first stage
1391 int otherStageMask = paint.getActiveStageMask() &
1392 (~(1 << GrPaint::kFirstTextureStage));
1393 if (otherStageMask) {
1394 target->preConcatSamplerMatrices(otherStageMask, m);
1395 }
1396
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1398 0, srcRect.height(), srcRect.fTop,
1399 0, 0, GrMatrix::I()[8]);
1400 if (NULL != srcMatrix) {
1401 m.postConcat(*srcMatrix);
1402 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001403 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001404
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001405 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1406 if (NULL == sqVB) {
1407 GrPrintf("Failed to create static rect vb.\n");
1408 return;
1409 }
1410 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1412#else
1413
1414 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001415#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001417#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001418 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1419#endif
1420
tomhudson@google.com93813632011-10-27 20:21:16 +00001421 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1422 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423 srcRects[0] = &srcRect;
1424 srcMatrices[0] = srcMatrix;
1425
1426 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1427#endif
1428}
1429
1430void GrContext::drawVertices(const GrPaint& paint,
1431 GrPrimitiveType primitiveType,
1432 int vertexCount,
1433 const GrPoint positions[],
1434 const GrPoint texCoords[],
1435 const GrColor colors[],
1436 const uint16_t indices[],
1437 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001438 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001439
1440 GrDrawTarget::AutoReleaseGeometry geo;
1441
1442 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1443
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001444 bool hasTexCoords[GrPaint::kTotalStages] = {
1445 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1446 0 // remaining stages use positions
1447 };
1448
1449 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001450
1451 if (NULL != colors) {
1452 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001453 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001454 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001455
1456 if (sizeof(GrPoint) != vertexSize) {
1457 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001458 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001459 return;
1460 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001461 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001462 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001463 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1464 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001465 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001466 NULL,
1467 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001468 void* curVertex = geo.vertices();
1469
1470 for (int i = 0; i < vertexCount; ++i) {
1471 *((GrPoint*)curVertex) = positions[i];
1472
1473 if (texOffsets[0] > 0) {
1474 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1475 }
1476 if (colorOffset > 0) {
1477 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1478 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001479 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001480 }
1481 } else {
1482 target->setVertexSourceToArray(layout, positions, vertexCount);
1483 }
1484
bsalomon@google.com91958362011-06-13 17:58:13 +00001485 // we don't currently apply offscreen AA to this path. Need improved
1486 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001487
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001488 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001489 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001490 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001491 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001492 target->drawNonIndexed(primitiveType, 0, vertexCount);
1493 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494}
1495
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001496///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001497
reed@google.com07f3ee12011-05-16 17:21:57 +00001498void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1499 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001500
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001501 if (path.isEmpty()) {
1502#if GR_DEBUG
1503 GrPrintf("Empty path should have been caught by canvas.\n");
1504#endif
1505 if (GrIsFillInverted(fill)) {
1506 this->drawPaint(paint);
1507 }
1508 return;
1509 }
1510
bsalomon@google.com27847de2011-02-22 20:59:41 +00001511 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001512
bsalomon@google.com289533a2011-10-27 12:34:25 +00001513 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1514
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001515 // An Assumption here is that path renderer would use some form of tweaking
1516 // the src color (either the input alpha or in the frag shader) to implement
1517 // aa. If we have some future driver-mojo path AA that can do the right
1518 // thing WRT to the blend then we'll need some query on the PR.
1519 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001520#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001521 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001522#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001523 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001524 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001525
1526 bool doOSAA = false;
1527 GrPathRenderer* pr = NULL;
1528 if (prAA) {
1529 pr = this->getPathRenderer(path, fill, true);
1530 if (NULL == pr) {
1531 prAA = false;
1532 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1533 pr = this->getPathRenderer(path, fill, false);
1534 }
1535 } else {
1536 pr = this->getPathRenderer(path, fill, false);
1537 }
1538
bsalomon@google.com30085192011-08-19 15:42:31 +00001539 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001540#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001541 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001542#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001543 return;
1544 }
1545
bsalomon@google.com289533a2011-10-27 12:34:25 +00001546 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.comee435122011-07-01 14:57:55 +00001547 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001548
bsalomon@google.com289533a2011-10-27 12:34:25 +00001549 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001550 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001551
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001552 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001553 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1554 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001555 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001556 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001557 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001558 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001559 return;
1560 }
1561 }
reed@google.com70c136e2011-06-03 19:51:26 +00001562
reed@google.com07f3ee12011-05-16 17:21:57 +00001563 GrRect pathBounds = path.getBounds();
1564 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001565 if (NULL != translate) {
1566 pathBounds.offset(*translate);
1567 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001568 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001569 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001570 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001571 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001572 return;
1573 }
1574 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001575 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001576 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1577 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001578 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1579 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1580 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001581 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001582 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1583 }
1584 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001585 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001586 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001587 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1588 GrRect rect;
1589 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001590 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1591 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001592 target->drawSimpleRect(rect, NULL, stageMask);
1593 }
1594 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001595 rect.iset(clipIBounds.fLeft, bound.fTop,
1596 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001597 target->drawSimpleRect(rect, NULL, stageMask);
1598 }
1599 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001600 rect.iset(bound.fRight, bound.fTop,
1601 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001602 target->drawSimpleRect(rect, NULL, stageMask);
1603 }
1604 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001605 rect.iset(clipIBounds.fLeft, bound.fBottom,
1606 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001607 target->drawSimpleRect(rect, NULL, stageMask);
1608 }
1609 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001610 return;
1611 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001612 }
1613 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001615
bsalomon@google.com27847de2011-02-22 20:59:41 +00001616////////////////////////////////////////////////////////////////////////////////
1617
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001618bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001619 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001620}
1621
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001622void GrContext::flush(int flagsBitfield) {
1623 if (kDiscard_FlushBit & flagsBitfield) {
1624 fDrawBuffer->reset();
1625 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001626 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001627 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001628 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001629 fGpu->forceRenderTargetFlush();
1630 }
1631}
1632
1633void GrContext::flushText() {
1634 if (kText_DrawCategory == fLastDrawCategory) {
1635 flushDrawBuffer();
1636 }
1637}
1638
1639void GrContext::flushDrawBuffer() {
1640#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001641 if (fDrawBuffer) {
1642 fDrawBuffer->playback(fGpu);
1643 fDrawBuffer->reset();
1644 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001645#endif
1646}
1647
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001648bool GrContext::readTexturePixels(GrTexture* texture,
1649 int left, int top, int width, int height,
1650 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001651 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001652
1653 // TODO: code read pixels for textures that aren't rendertargets
1654
1655 this->flush();
1656 GrRenderTarget* target = texture->asRenderTarget();
1657 if (NULL != target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001658 return this->readRenderTargetPixels(target,
1659 left, top, width, height,
1660 config, buffer, 0);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001661 } else {
1662 return false;
1663 }
1664}
1665
1666bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
bsalomon@google.comc6980972011-11-02 19:57:21 +00001667 int left, int top, int width, int height,
1668 GrPixelConfig config, void* buffer,
1669 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001670 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001671 if (NULL == target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001672 target = fGpu->getRenderTarget();
1673 if (NULL == target) {
1674 return false;
1675 }
1676 }
1677
1678 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1679 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1680 // not supported at this time.
1681 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1682 !GrPixelConfigIsUnpremultiplied(config)) {
1683 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001684 }
1685
bsalomon@google.comc4364992011-11-07 15:54:49 +00001686 this->flush();
1687
1688 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001689 bool swapRAndB = NULL != src &&
1690 fGpu->preferredReadPixelsConfig(config) ==
1691 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001692
1693 bool flipY = NULL != src &&
1694 fGpu->readPixelsWillPayForYFlip(target, left, top,
1695 width, height, config,
1696 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001697 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1698 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001699
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001700 if (NULL == src && alphaConversion) {
1701 // we should fallback to cpu conversion here. This could happen when
1702 // we were given an external render target by the client that is not
1703 // also a texture (e.g. FBO 0 in GL)
1704 return false;
1705 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001706 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001707 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001708 if (flipY || swapRAndB || alphaConversion) {
1709 GrAssert(NULL != src);
1710 if (swapRAndB) {
1711 config = GrPixelConfigSwapRAndB(config);
1712 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001713 }
1714 // Make the scratch a render target because we don't have a robust
1715 // readTexturePixels as of yet (it calls this function).
1716 const GrTextureDesc desc = {
1717 kRenderTarget_GrTextureFlagBit,
1718 kNone_GrAALevel,
1719 width, height,
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001720 { config }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001721 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001722
1723 ast.set(this, desc);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001724 GrTexture* texture = ast.texture();
1725 if (!texture) {
1726 return false;
1727 }
1728 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001729 GrAssert(NULL != target);
1730
1731 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001732 reset_target_state(fGpu);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001733
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001734 fGpu->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001735
1736 GrSamplerState sampler;
1737 sampler.setClampNoFilter();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001738 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001739 GrMatrix matrix;
1740 if (flipY) {
1741 matrix.setTranslate(SK_Scalar1 * left,
1742 SK_Scalar1 * (top + height));
1743 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1744 } else {
1745 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1746 }
1747 matrix.postIDiv(src->width(), src->height());
1748 sampler.setMatrix(matrix);
1749 fGpu->setSamplerState(0, sampler);
1750 fGpu->setTexture(0, src);
1751 GrRect rect;
1752 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1753 fGpu->drawSimpleRect(rect, NULL, 0x1);
1754 left = 0;
1755 top = 0;
1756 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001757 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001758 left, top, width, height,
1759 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001760}
1761
1762void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001763 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001764 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001765 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001766
1767 // TODO: when underlying api has a direct way to do this we should use it
1768 // (e.g. glDrawPixels on desktop GL).
1769
bsalomon@google.comc4364992011-11-07 15:54:49 +00001770 this->flush(kForceCurrentRenderTarget_FlushBit);
bsalomon@google.com5c638652011-07-18 19:31:59 +00001771
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001772 const GrTextureDesc desc = {
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001773 kNone_GrTextureFlags, kNone_GrAALevel, width, height, { config }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001774 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001775 GrAutoScratchTexture ast(this, desc);
1776 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001777 if (NULL == texture) {
1778 return;
1779 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001780 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001781
bsalomon@google.com27847de2011-02-22 20:59:41 +00001782 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001783 reset_target_state(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001784
1785 GrMatrix matrix;
1786 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1787 fGpu->setViewMatrix(matrix);
1788
bsalomon@google.com27847de2011-02-22 20:59:41 +00001789 fGpu->setTexture(0, texture);
1790
1791 GrSamplerState sampler;
1792 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001793 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001794 sampler.setMatrix(matrix);
1795 fGpu->setSamplerState(0, sampler);
1796
1797 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1798 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001799 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001800 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1801 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001802 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001803 return;
1804 }
1805 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1806 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1807}
1808////////////////////////////////////////////////////////////////////////////////
1809
1810void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001811
1812 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1813 int s = i + GrPaint::kFirstTextureStage;
1814 target->setTexture(s, paint.getTexture(i));
1815 target->setSamplerState(s, *paint.getTextureSampler(i));
1816 }
1817
1818 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1819
1820 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1821 int s = i + GrPaint::kFirstMaskStage;
1822 target->setTexture(s, paint.getMask(i));
1823 target->setSamplerState(s, *paint.getMaskSampler(i));
1824 }
1825
bsalomon@google.com27847de2011-02-22 20:59:41 +00001826 target->setColor(paint.fColor);
1827
1828 if (paint.fDither) {
1829 target->enableState(GrDrawTarget::kDither_StateBit);
1830 } else {
1831 target->disableState(GrDrawTarget::kDither_StateBit);
1832 }
1833 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001834 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001835 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001836 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001837 }
1838 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001839 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001840
1841 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1842 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1843 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001844}
1845
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001846GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001847 DrawCategory category) {
1848 if (category != fLastDrawCategory) {
1849 flushDrawBuffer();
1850 fLastDrawCategory = category;
1851 }
1852 SetPaint(paint, fGpu);
1853 GrDrawTarget* target = fGpu;
1854 switch (category) {
1855 case kText_DrawCategory:
1856#if DEFER_TEXT_RENDERING
1857 target = fDrawBuffer;
1858 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1859#else
1860 target = fGpu;
1861#endif
1862 break;
1863 case kUnbuffered_DrawCategory:
1864 target = fGpu;
1865 break;
1866 case kBuffered_DrawCategory:
1867 target = fDrawBuffer;
1868 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1869 break;
1870 }
1871 return target;
1872}
1873
bsalomon@google.com289533a2011-10-27 12:34:25 +00001874GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1875 GrPathFill fill,
1876 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001877 if (NULL == fPathRendererChain) {
1878 fPathRendererChain =
1879 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1880 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001881 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1882 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001883}
1884
bsalomon@google.com27847de2011-02-22 20:59:41 +00001885////////////////////////////////////////////////////////////////////////////////
1886
bsalomon@google.com27847de2011-02-22 20:59:41 +00001887void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001888 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889 fGpu->setRenderTarget(target);
1890}
1891
1892GrRenderTarget* GrContext::getRenderTarget() {
1893 return fGpu->getRenderTarget();
1894}
1895
1896const GrRenderTarget* GrContext::getRenderTarget() const {
1897 return fGpu->getRenderTarget();
1898}
1899
1900const GrMatrix& GrContext::getMatrix() const {
1901 return fGpu->getViewMatrix();
1902}
1903
1904void GrContext::setMatrix(const GrMatrix& m) {
1905 fGpu->setViewMatrix(m);
1906}
1907
1908void GrContext::concatMatrix(const GrMatrix& m) const {
1909 fGpu->preConcatViewMatrix(m);
1910}
1911
1912static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1913 intptr_t mask = 1 << shift;
1914 if (pred) {
1915 bits |= mask;
1916 } else {
1917 bits &= ~mask;
1918 }
1919 return bits;
1920}
1921
1922void GrContext::resetStats() {
1923 fGpu->resetStats();
1924}
1925
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001926const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001927 return fGpu->getStats();
1928}
1929
1930void GrContext::printStats() const {
1931 fGpu->printStats();
1932}
1933
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001934GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001935 fGpu = gpu;
1936 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001937 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001938
bsalomon@google.com30085192011-08-19 15:42:31 +00001939 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001940
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001941 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1942 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001943 fFontCache = new GrFontCache(fGpu);
1944
1945 fLastDrawCategory = kUnbuffered_DrawCategory;
1946
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001947 fDrawBuffer = NULL;
1948 fDrawBufferVBAllocPool = NULL;
1949 fDrawBufferIBAllocPool = NULL;
1950
bsalomon@google.com205d4602011-04-25 12:43:45 +00001951 fAAFillRectIndexBuffer = NULL;
1952 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001953
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001954 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
1955 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001956 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1957 }
1958 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001959
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001960 this->setupDrawBuffer();
1961}
1962
1963void GrContext::setupDrawBuffer() {
1964
1965 GrAssert(NULL == fDrawBuffer);
1966 GrAssert(NULL == fDrawBufferVBAllocPool);
1967 GrAssert(NULL == fDrawBufferIBAllocPool);
1968
bsalomon@google.com27847de2011-02-22 20:59:41 +00001969#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001970 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001971 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001972 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1973 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001974 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001975 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001976 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001977 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1978
bsalomon@google.com471d4712011-08-23 15:45:25 +00001979 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1980 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001981 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982#endif
1983
1984#if BATCH_RECT_TO_RECT
1985 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1986#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001987}
1988
bsalomon@google.com27847de2011-02-22 20:59:41 +00001989GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1990 GrDrawTarget* target;
1991#if DEFER_TEXT_RENDERING
1992 target = prepareToDraw(paint, kText_DrawCategory);
1993#else
1994 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1995#endif
1996 SetPaint(paint, target);
1997 return target;
1998}
1999
2000const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2001 return fGpu->getQuadIndexBuffer();
2002}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002003
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002004void GrContext::convolveInX(GrTexture* texture,
2005 const SkRect& rect,
2006 const float* kernel,
2007 int kernelWidth) {
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002008 float imageIncrement[2] = {1.0f / texture->allocatedWidth(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002009 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2010}
2011
2012void GrContext::convolveInY(GrTexture* texture,
2013 const SkRect& rect,
2014 const float* kernel,
2015 int kernelWidth) {
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002016 float imageIncrement[2] = {0.0f, 1.0f / texture->allocatedHeight()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002017 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2018}
2019
2020void GrContext::convolve(GrTexture* texture,
2021 const SkRect& rect,
2022 float imageIncrement[2],
2023 const float* kernel,
2024 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002025 GrDrawTarget::AutoStateRestore asr(fGpu);
2026 GrMatrix sampleM;
2027 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
2028 GrSamplerState::kClamp_WrapMode,
2029 GrSamplerState::kConvolution_Filter);
2030 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002031 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002032 sampler.setMatrix(sampleM);
2033 fGpu->setSamplerState(0, sampler);
2034 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002035 fGpu->setTexture(0, texture);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002036 fGpu->setColor(0xFFFFFFFF);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002037 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002038 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2039}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002040
2041///////////////////////////////////////////////////////////////////////////////