blob: 1767f06f4c7767efe6e32a06730c570b44a18d9d [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
bsalomon@google.com1fadb202011-12-12 16:10:08 +000010#include "GrContext.h"
11
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000014#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015#include "GrIndexBuffer.h"
16#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000017#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000018#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000020#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000021#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000022#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000023#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024
bsalomon@google.com91958362011-06-13 17:58:13 +000025// Using MSAA seems to be slower for some yet unknown reason.
26#define PREFER_MSAA_OFFSCREEN_AA 0
27#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000028
bsalomon@google.com27847de2011-02-22 20:59:41 +000029#define DEFER_TEXT_RENDERING 1
30
31#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
32
bsalomon@google.comd46e2422011-09-23 17:40:07 +000033// When we're using coverage AA but the blend is incompatible (given gpu
34// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000035#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000036
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000037static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000039
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
bsalomon@google.combc4b6542011-11-19 13:56:11 +000048#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
49
bsalomon@google.com05ef5102011-05-02 21:14:59 +000050GrContext* GrContext::Create(GrEngine engine,
51 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000052 GrContext* ctx = NULL;
53 GrGpu* fGpu = GrGpu::Create(engine, context3D);
54 if (NULL != fGpu) {
55 ctx = new GrContext(fGpu);
56 fGpu->unref();
57 }
58 return ctx;
59}
60
bsalomon@google.com27847de2011-02-22 20:59:41 +000061GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000068
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000072 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000073}
74
bsalomon@google.com8fe72472011-03-30 21:26:44 +000075void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000076 contextDestroyed();
77 this->setupDrawBuffer();
78}
79
80void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 // abandon first to so destructors
82 // don't try to free the resources in the API.
83 fGpu->abandonResources();
84
bsalomon@google.com30085192011-08-19 15:42:31 +000085 // a path renderer may be holding onto resources that
86 // are now unusable
87 GrSafeSetNull(fPathRendererChain);
88
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBuffer;
90 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferVBAllocPool;
93 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000094
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 delete fDrawBufferIBAllocPool;
96 fDrawBufferIBAllocPool = NULL;
97
bsalomon@google.com205d4602011-04-25 12:43:45 +000098 GrSafeSetNull(fAAFillRectIndexBuffer);
99 GrSafeSetNull(fAAStrokeRectIndexBuffer);
100
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101 fTextureCache->removeAll();
102 fFontCache->freeAll();
103 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000104}
105
106void GrContext::resetContext() {
107 fGpu->markContextDirty();
108}
109
110void GrContext::freeGpuResources() {
111 this->flush();
112 fTextureCache->removeAll();
113 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000114 // a path renderer may be holding onto resources
115 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000116}
117
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000118////////////////////////////////////////////////////////////////////////////////
119
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000120int GrContext::PaintStageVertexLayoutBits(
121 const GrPaint& paint,
122 const bool hasTexCoords[GrPaint::kTotalStages]) {
123 int stageMask = paint.getActiveStageMask();
124 int layout = 0;
125 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
126 if ((1 << i) & stageMask) {
127 if (NULL != hasTexCoords && hasTexCoords[i]) {
128 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
129 } else {
130 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
131 }
132 }
133 }
134 return layout;
135}
136
137
138////////////////////////////////////////////////////////////////////////////////
139
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000140enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000141 // flags for textures
142 kNPOTBit = 0x1,
143 kFilterBit = 0x2,
144 kScratchBit = 0x4,
145
146 // resource type
147 kTextureBit = 0x8,
148 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000149};
150
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000151GrTexture* GrContext::TextureCacheEntry::texture() const {
152 if (NULL == fEntry) {
153 return NULL;
154 } else {
155 return (GrTexture*) fEntry->resource();
156 }
157}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000158
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000159namespace {
160// returns true if this is a "special" texture because of gpu NPOT limitations
161bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000162 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163 GrContext::TextureKey clientKey,
164 int width,
165 int height,
166 bool scratch,
167 uint32_t v[4]) {
168 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
169 // we assume we only need 16 bits of width and height
170 // assert that texture creation will fail anyway if this assumption
171 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000172 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000173 v[0] = clientKey & 0xffffffffUL;
174 v[1] = (clientKey >> 32) & 0xffffffffUL;
175 v[2] = width | (height << 16);
176
177 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000178 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
180
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000181 bool tiled = NULL != sampler &&
182 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
183 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184
185 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000187 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 }
190 }
191 }
192
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 if (scratch) {
194 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197 v[3] |= kTextureBit;
198
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199 return v[3] & kNPOTBit;
200}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000201
202// we should never have more than one stencil buffer with same combo of
203// (width,height,samplecount)
204void gen_stencil_key_values(int width, int height,
205 int sampleCnt, uint32_t v[4]) {
206 v[0] = width;
207 v[1] = height;
208 v[2] = sampleCnt;
209 v[3] = kStencilBufferBit;
210}
211
212void gen_stencil_key_values(const GrStencilBuffer* sb,
213 uint32_t v[4]) {
214 gen_stencil_key_values(sb->width(), sb->height(),
215 sb->numSamples(), v);
216}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000217
218// This should be subsumed by a future version of GrDrawState
219// It does not reset stage textures/samplers or per-vertex-edge-aa state since
220// they aren't used unless the vertex layout references them.
221// It also doesn't set the render target.
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000222void reset_draw_state(GrDrawState* drawState){
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000223
224 drawState->setViewMatrix(GrMatrix::I());
225 drawState->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000226 drawState->resetStateFlags();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000227 drawState->setEdgeAAData(NULL, 0);
228 drawState->disableStencil();
229 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000230 drawState->setBlendFunc(kOne_BlendCoeff,
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000231 kZero_BlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000232 drawState->setFirstCoverageStage(GrDrawState::kNumStages);
233 drawState->setDrawFace(GrDrawState::kBoth_DrawFace);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000234}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000235}
236
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000237GrContext::TextureCacheEntry GrContext::findAndLockTexture(
238 TextureKey key,
239 int width,
240 int height,
241 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000242 uint32_t v[4];
243 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
244 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000245 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
246 GrResourceCache::kNested_LockType));
247}
248
bsalomon@google.comfb309512011-11-30 14:13:48 +0000249bool GrContext::isTextureInCache(TextureKey key,
250 int width,
251 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000252 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000253 uint32_t v[4];
254 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
255 GrResourceKey resourceKey(v);
256 return fTextureCache->hasKey(resourceKey);
257}
258
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000259GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000260 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000261 uint32_t v[4];
262 gen_stencil_key_values(sb, v);
263 GrResourceKey resourceKey(v);
264 return fTextureCache->createAndLock(resourceKey, sb);
265}
266
267GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
268 int sampleCnt) {
269 uint32_t v[4];
270 gen_stencil_key_values(width, height, sampleCnt, v);
271 GrResourceKey resourceKey(v);
272 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
273 GrResourceCache::kSingle_LockType);
274 if (NULL != entry) {
275 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
276 return sb;
277 } else {
278 return NULL;
279 }
280}
281
282void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000283 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000284 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000285}
286
287static void stretchImage(void* dst,
288 int dstW,
289 int dstH,
290 void* src,
291 int srcW,
292 int srcH,
293 int bpp) {
294 GrFixed dx = (srcW << 16) / dstW;
295 GrFixed dy = (srcH << 16) / dstH;
296
297 GrFixed y = dy >> 1;
298
299 int dstXLimit = dstW*bpp;
300 for (int j = 0; j < dstH; ++j) {
301 GrFixed x = dx >> 1;
302 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
303 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
304 for (int i = 0; i < dstXLimit; i += bpp) {
305 memcpy((uint8_t*) dstRow + i,
306 (uint8_t*) srcRow + (x>>16)*bpp,
307 bpp);
308 x += dx;
309 }
310 y += dy;
311 }
312}
313
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000314GrContext::TextureCacheEntry GrContext::createAndLockTexture(
315 TextureKey key,
316 const GrSamplerState* sampler,
317 const GrTextureDesc& desc,
318 void* srcData,
319 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000320 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000321
322#if GR_DUMP_TEXTURE_UPLOAD
323 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
324#endif
325
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000326 TextureCacheEntry entry;
327 uint32_t v[4];
328 bool special = gen_texture_key_values(fGpu, sampler, key,
329 desc.fWidth, desc.fHeight, false, v);
330 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000331
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000332 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000333 GrAssert(NULL != sampler);
334 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
335 desc.fWidth,
336 desc.fHeight,
337 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000338
339 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000340 clampEntry = this->createAndLockTexture(key, NULL, desc,
341 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000342 GrAssert(NULL != clampEntry.texture());
343 if (NULL == clampEntry.texture()) {
344 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000345 }
346 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000347 GrTextureDesc rtDesc = desc;
348 rtDesc.fFlags = rtDesc.fFlags |
349 kRenderTarget_GrTextureFlagBit |
350 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000351 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
352 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000353
354 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
355
356 if (NULL != texture) {
357 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000358 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000359 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000360 drawState->setRenderTarget(texture->asRenderTarget());
361 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000362
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000363 GrSamplerState::Filter filter;
364 // if filtering is not desired then we want to ensure all
365 // texels in the resampled image are copies of texels from
366 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000367 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000368 filter = GrSamplerState::kNearest_Filter;
369 } else {
370 filter = GrSamplerState::kBilinear_Filter;
371 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000372 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
373 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000374
375 static const GrVertexLayout layout =
376 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
377 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
378
379 if (arg.succeeded()) {
380 GrPoint* verts = (GrPoint*) arg.vertices();
381 verts[0].setIRectFan(0, 0,
382 texture->width(),
383 texture->height(),
384 2*sizeof(GrPoint));
385 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
386 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
387 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000388 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000390 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 } else {
392 // TODO: Our CPU stretch doesn't filter. But we create separate
393 // stretched textures when the sampler state is either filtered or
394 // not. Either implement filtered stretch blit on CPU or just create
395 // one when FBO case fails.
396
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000397 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 // no longer need to clamp at min RT size.
399 rtDesc.fWidth = GrNextPow2(desc.fWidth);
400 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000401 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000402 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000403 rtDesc.fWidth *
404 rtDesc.fHeight);
405 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
406 srcData, desc.fWidth, desc.fHeight, bpp);
407
408 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
409
410 GrTexture* texture = fGpu->createTexture(rtDesc,
411 stretchedPixels.get(),
412 stretchedRowBytes);
413 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000417
418 } else {
419 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
420 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000422 }
423 }
424 return entry;
425}
426
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427namespace {
428inline void gen_scratch_tex_key_values(const GrGpu* gpu,
429 const GrTextureDesc& desc,
430 uint32_t v[4]) {
431 // Instead of a client-provided key of the texture contents
432 // we create a key of from the descriptor.
433 GrContext::TextureKey descKey = desc.fAALevel |
434 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000435 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000436 // this code path isn't friendly to tiling with NPOT restricitons
437 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000438 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
439 desc.fHeight, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000440}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000441}
442
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000443GrContext::TextureCacheEntry GrContext::lockScratchTexture(
444 const GrTextureDesc& inDesc,
445 ScratchTexMatch match) {
446
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000447 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000448 if (kExact_ScratchTexMatch != match) {
449 // bin by pow2 with a reasonable min
450 static const int MIN_SIZE = 256;
451 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
452 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
453 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000454
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000455 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000456 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
457
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000458 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000459 int origWidth = desc.fWidth;
460 int origHeight = desc.fHeight;
461 bool doubledW = false;
462 bool doubledH = false;
463
464 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000465 uint32_t v[4];
466 gen_scratch_tex_key_values(fGpu, desc, v);
467 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000468 entry = fTextureCache->findAndLock(key,
469 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000470 // if we miss, relax the fit of the flags...
471 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000472 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000473 break;
474 }
475 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
476 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
477 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
478 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
479 } else if (!doubledW) {
480 desc.fFlags = inDesc.fFlags;
481 desc.fWidth *= 2;
482 doubledW = true;
483 } else if (!doubledH) {
484 desc.fFlags = inDesc.fFlags;
485 desc.fWidth = origWidth;
486 desc.fHeight *= 2;
487 doubledH = true;
488 } else {
489 break;
490 }
491
492 } while (true);
493
494 if (NULL == entry) {
495 desc.fFlags = inDesc.fFlags;
496 desc.fWidth = origWidth;
497 desc.fHeight = origHeight;
498 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
499 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000500 uint32_t v[4];
501 gen_scratch_tex_key_values(fGpu, desc, v);
502 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000503 entry = fTextureCache->createAndLock(key, texture);
504 }
505 }
506
507 // If the caller gives us the same desc/sampler twice we don't want
508 // to return the same texture the second time (unless it was previously
509 // released). So we detach the entry from the cache and reattach at release.
510 if (NULL != entry) {
511 fTextureCache->detach(entry);
512 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000514}
515
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000516void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000517 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518 // If this is a scratch texture we detached it from the cache
519 // while it was locked (to avoid two callers simultaneously getting
520 // the same texture).
521 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
522 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000523 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000524 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000525 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000526}
527
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000528GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000529 void* srcData,
530 size_t rowBytes) {
531 return fGpu->createTexture(desc, srcData, rowBytes);
532}
533
534void GrContext::getTextureCacheLimits(int* maxTextures,
535 size_t* maxTextureBytes) const {
536 fTextureCache->getLimits(maxTextures, maxTextureBytes);
537}
538
539void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
540 fTextureCache->setLimits(maxTextures, maxTextureBytes);
541}
542
bsalomon@google.com91958362011-06-13 17:58:13 +0000543int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000544 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000545}
546
547int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000548 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000549}
550
551///////////////////////////////////////////////////////////////////////////////
552
bsalomon@google.come269f212011-11-07 13:29:52 +0000553GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
554 return fGpu->createPlatformTexture(desc);
555}
556
557GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
558 return fGpu->createPlatformRenderTarget(desc);
559}
560
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000561GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
562 // validate flags here so that GrGpu subclasses don't have to check
563 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
564 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000565 return NULL;
566 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000567 if (desc.fSampleCnt &&
568 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000569 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000570 }
571 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
572 desc.fSampleCnt &&
573 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
574 return NULL;
575 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000576 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577}
578
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000579///////////////////////////////////////////////////////////////////////////////
580
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000581bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000582 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000583 const GrDrawTarget::Caps& caps = fGpu->getCaps();
584 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000585 return false;
586 }
587
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
589
590 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000591 bool tiled = NULL != sampler &&
592 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
593 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000594 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000595 return false;
596 }
597 }
598 return true;
599}
600
601////////////////////////////////////////////////////////////////////////////////
602
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000603const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
604
bsalomon@google.com27847de2011-02-22 20:59:41 +0000605void GrContext::setClip(const GrClip& clip) {
606 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000607 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000608}
609
610void GrContext::setClip(const GrIRect& rect) {
611 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000612 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000613 fGpu->setClip(clip);
614}
615
616////////////////////////////////////////////////////////////////////////////////
617
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000618void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000619 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000620 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000621}
622
623void GrContext::drawPaint(const GrPaint& paint) {
624 // set rect to be big enough to fill the space, but not super-huge, so we
625 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000626 GrRect r;
627 r.setLTRB(0, 0,
628 GrIntToScalar(getRenderTarget()->width()),
629 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000630 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000631 SkTLazy<GrPaint> tmpPaint;
632 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000633 GrDrawState* drawState = fGpu->drawState();
634 GrAutoMatrix am;
635
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000636 // We attempt to map r by the inverse matrix and draw that. mapRect will
637 // map the four corners and bound them with a new rect. This will not
638 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000639 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000640 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000641 GrPrintf("Could not invert matrix");
642 return;
643 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000644 inverse.mapRect(&r);
645 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000646 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000647 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000648 GrPrintf("Could not invert matrix");
649 return;
650 }
651 tmpPaint.set(paint);
652 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
653 p = tmpPaint.get();
654 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000655 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000657 // by definition this fills the entire clip, no need for AA
658 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000659 if (!tmpPaint.isValid()) {
660 tmpPaint.set(paint);
661 p = tmpPaint.get();
662 }
663 GrAssert(p == tmpPaint.get());
664 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000665 }
666 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000667}
668
bsalomon@google.com205d4602011-04-25 12:43:45 +0000669////////////////////////////////////////////////////////////////////////////////
670
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000671namespace {
672inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
673 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
674}
675}
676
bsalomon@google.com91958362011-06-13 17:58:13 +0000677struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000678 enum Downsample {
bsalomon@google.com91958362011-06-13 17:58:13 +0000679 k4x4SinglePass_Downsample,
680 kFSAA_Downsample
681 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000682 int fTileSizeX;
683 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000684 int fTileCountX;
685 int fTileCountY;
686 int fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000687 GrAutoScratchTexture fOffscreen;
bsalomon@google.com91958362011-06-13 17:58:13 +0000688 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000689 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000690};
691
bsalomon@google.com471d4712011-08-23 15:45:25 +0000692bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000693 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000694#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000695 return false;
696#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000697 // Line primitves are always rasterized as 1 pixel wide.
698 // Super-sampling would make them too thin but MSAA would be OK.
699 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000700 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000701 return false;
702 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000703 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000704 return false;
705 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000706 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000707#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000708 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000709#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000710 return false;
711 }
712 return true;
713#endif
714}
715
bsalomon@google.com91958362011-06-13 17:58:13 +0000716bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000717 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000718 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000719 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000720 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000721
722 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000723
bsalomon@google.com46579e02012-01-11 18:51:15 +0000724 GrAssert(NULL == record->fOffscreen.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000725 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000726
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000727 int boundW = boundRect.width();
728 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000729
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000730 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000731
732 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
733 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
734
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000735 if (requireStencil) {
736 desc.fFlags = kRenderTarget_GrTextureFlagBit;
737 } else {
738 desc.fFlags = kRenderTarget_GrTextureFlagBit |
739 kNoStencil_GrTextureFlagBit;
740 }
741
bsalomon@google.comc4364992011-11-07 15:54:49 +0000742 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000743
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000744 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000745 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000746 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000747 desc.fAALevel = kMed_GrAALevel;
748 } else {
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000749 record->fDownsample = OffscreenRecord::k4x4SinglePass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000750 record->fScale = OFFSCREEN_SSAA_SCALE;
751 // both downsample paths assume this
752 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000753 desc.fAALevel = kNone_GrAALevel;
754 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000755
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000756 desc.fWidth *= record->fScale;
757 desc.fHeight *= record->fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000758 record->fOffscreen.set(this, desc);
759 if (NULL == record->fOffscreen.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000760 return false;
761 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000762 // the approximate lookup might have given us some slop space, might as well
763 // use it when computing the tiles size.
764 // these are scale values, will adjust after considering
765 // the possible second offscreen.
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000766 record->fTileSizeX = record->fOffscreen.texture()->width();
767 record->fTileSizeY = record->fOffscreen.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000769 record->fTileSizeX /= record->fScale;
770 record->fTileSizeY /= record->fScale;
771
772 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
773 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
774
tomhudson@google.com237a4612011-07-19 15:44:00 +0000775 record->fClip = target->getClip();
776
bsalomon@google.com91958362011-06-13 17:58:13 +0000777 target->saveCurrentDrawState(&record->fSavedState);
778 return true;
779}
780
781void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
782 const GrIRect& boundRect,
783 int tileX, int tileY,
784 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000785
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000786 GrRenderTarget* offRT = record->fOffscreen.texture()->asRenderTarget();
787 GrAssert(NULL != offRT);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000788
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000789 GrPaint tempPaint;
790 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000791 this->setPaint(tempPaint, target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000792 GrDrawState* drawState = target->drawState();
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000793 drawState->setRenderTarget(offRT);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000794#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com337af172012-01-11 16:00:42 +0000795 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000796#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000797
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000798 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000799 int left = boundRect.fLeft + tileX * record->fTileSizeX;
800 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000801 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000802 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000803 GrMatrix scaleM;
804 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000805 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000806
bsalomon@google.com91958362011-06-13 17:58:13 +0000807 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000808 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000809 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000811 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
812 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000813 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000814#if 0
815 // visualize tile boundaries by setting edges of offscreen to white
816 // and interior to tranparent. black.
817 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000818
bsalomon@google.com91958362011-06-13 17:58:13 +0000819 static const int gOffset = 2;
820 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
821 record->fScale * w - gOffset,
822 record->fScale * h - gOffset);
823 target->clear(&clear2, 0x0);
824#else
825 target->clear(&clear, 0x0);
826#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000827}
828
bsalomon@google.com91958362011-06-13 17:58:13 +0000829void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000830 const GrPaint& paint,
831 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000832 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000833 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000834 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com46579e02012-01-11 18:51:15 +0000835 GrAssert(NULL != record->fOffscreen.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000836 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000837 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000838 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
839 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000840 tileRect.fRight = (tileX == record->fTileCountX-1) ?
841 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000842 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000843 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
844 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000845 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000846
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000847 GrSamplerState::Filter filter;
848 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
849 filter = GrSamplerState::k4x4Downsample_Filter;
850 } else {
851 filter = GrSamplerState::kBilinear_Filter;
852 }
853
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000854 GrTexture* src = record->fOffscreen.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000855 int scale;
856
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000857 enum {
858 kOffscreenStage = GrPaint::kTotalStages,
859 };
860
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000861 GrDrawState* drawState = target->drawState();
862
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000863 if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000865 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000866 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000867 } else {
868 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
869 record->fDownsample);
870 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871 }
872
bsalomon@google.com91958362011-06-13 17:58:13 +0000873 // setup for draw back to main RT, we use the original
874 // draw state setup by the caller plus an additional coverage
875 // stage to handle the AA resolve. Also, we use an identity
876 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000877 int stageMask = paint.getActiveStageMask();
878
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000879 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000880 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000881
882 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000883 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000884 if (drawState->getViewInverse(&invVM)) {
885 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000886 }
887 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000888 // This is important when tiling, otherwise second tile's
889 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000890 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000891
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000892 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000893 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
894 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000895 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
896 scale * GR_Scalar1 / src->height());
897 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
898 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000899
reed@google.com20efde72011-05-09 17:00:02 +0000900 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000901 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000902 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000903 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000904}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000905
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000906void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
907 GrPathRenderer* pr,
908 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000909 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000910}
911
912////////////////////////////////////////////////////////////////////////////////
913
bsalomon@google.com27847de2011-02-22 20:59:41 +0000914/* create a triangle strip that strokes the specified triangle. There are 8
915 unique vertices, but we repreat the last 2 to close up. Alternatively we
916 could use an indices array, and then only send 8 verts, but not sure that
917 would be faster.
918 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000919static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000920 GrScalar width) {
921 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000922 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000923
924 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
925 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
926 verts[2].set(rect.fRight - rad, rect.fTop + rad);
927 verts[3].set(rect.fRight + rad, rect.fTop - rad);
928 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
929 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
930 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
931 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
932 verts[8] = verts[0];
933 verts[9] = verts[1];
934}
935
bsalomon@google.com205d4602011-04-25 12:43:45 +0000936static void setInsetFan(GrPoint* pts, size_t stride,
937 const GrRect& r, GrScalar dx, GrScalar dy) {
938 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
939}
940
941static const uint16_t gFillAARectIdx[] = {
942 0, 1, 5, 5, 4, 0,
943 1, 2, 6, 6, 5, 1,
944 2, 3, 7, 7, 6, 2,
945 3, 0, 4, 4, 7, 3,
946 4, 5, 6, 6, 7, 4,
947};
948
949int GrContext::aaFillRectIndexCount() const {
950 return GR_ARRAY_COUNT(gFillAARectIdx);
951}
952
953GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
954 if (NULL == fAAFillRectIndexBuffer) {
955 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
956 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000957 if (NULL != fAAFillRectIndexBuffer) {
958 #if GR_DEBUG
959 bool updated =
960 #endif
961 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
962 sizeof(gFillAARectIdx));
963 GR_DEBUGASSERT(updated);
964 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000965 }
966 return fAAFillRectIndexBuffer;
967}
968
969static const uint16_t gStrokeAARectIdx[] = {
970 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
971 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
972 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
973 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
974
975 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
976 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
977 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
978 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
979
980 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
981 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
982 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
983 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
984};
985
986int GrContext::aaStrokeRectIndexCount() const {
987 return GR_ARRAY_COUNT(gStrokeAARectIdx);
988}
989
990GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
991 if (NULL == fAAStrokeRectIndexBuffer) {
992 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
993 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000994 if (NULL != fAAStrokeRectIndexBuffer) {
995 #if GR_DEBUG
996 bool updated =
997 #endif
998 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
999 sizeof(gStrokeAARectIdx));
1000 GR_DEBUGASSERT(updated);
1001 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001002 }
1003 return fAAStrokeRectIndexBuffer;
1004}
1005
bsalomon@google.coma3108262011-10-10 14:08:47 +00001006static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1007 bool useCoverage) {
1008 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001009 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001010 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001011 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1012 }
1013 }
1014 if (useCoverage) {
1015 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1016 } else {
1017 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1018 }
1019 return layout;
1020}
1021
bsalomon@google.com205d4602011-04-25 12:43:45 +00001022void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001023 const GrRect& devRect,
1024 bool useVertexCoverage) {
1025 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001026
1027 size_t vsize = GrDrawTarget::VertexSize(layout);
1028
1029 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001030 if (!geo.succeeded()) {
1031 GrPrintf("Failed to get space for vertices!\n");
1032 return;
1033 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001034 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1035 if (NULL == indexBuffer) {
1036 GrPrintf("Failed to create index buffer!\n");
1037 return;
1038 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001039
1040 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1041
1042 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1043 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1044
1045 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1046 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1047
1048 verts += sizeof(GrPoint);
1049 for (int i = 0; i < 4; ++i) {
1050 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1051 }
1052
bsalomon@google.coma3108262011-10-10 14:08:47 +00001053 GrColor innerColor;
1054 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001055 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001056 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001057 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 }
1059
bsalomon@google.com205d4602011-04-25 12:43:45 +00001060 verts += 4 * vsize;
1061 for (int i = 0; i < 4; ++i) {
1062 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1063 }
1064
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001065 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001066
1067 target->drawIndexed(kTriangles_PrimitiveType, 0,
1068 0, 8, this->aaFillRectIndexCount());
1069}
1070
bsalomon@google.coma3108262011-10-10 14:08:47 +00001071void GrContext::strokeAARect(GrDrawTarget* target,
1072 const GrRect& devRect,
1073 const GrVec& devStrokeSize,
1074 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001075 const GrScalar& dx = devStrokeSize.fX;
1076 const GrScalar& dy = devStrokeSize.fY;
1077 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1078 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1079
bsalomon@google.com205d4602011-04-25 12:43:45 +00001080 GrScalar spare;
1081 {
1082 GrScalar w = devRect.width() - dx;
1083 GrScalar h = devRect.height() - dy;
1084 spare = GrMin(w, h);
1085 }
1086
1087 if (spare <= 0) {
1088 GrRect r(devRect);
1089 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001090 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001091 return;
1092 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001093 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001094 size_t vsize = GrDrawTarget::VertexSize(layout);
1095
1096 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001097 if (!geo.succeeded()) {
1098 GrPrintf("Failed to get space for vertices!\n");
1099 return;
1100 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001101 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1102 if (NULL == indexBuffer) {
1103 GrPrintf("Failed to create index buffer!\n");
1104 return;
1105 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001106
1107 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1108
1109 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1110 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1111 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1112 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1113
1114 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1115 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1116 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1117 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1118
1119 verts += sizeof(GrPoint);
1120 for (int i = 0; i < 4; ++i) {
1121 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1122 }
1123
bsalomon@google.coma3108262011-10-10 14:08:47 +00001124 GrColor innerColor;
1125 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001126 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001127 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001128 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001129 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001130 verts += 4 * vsize;
1131 for (int i = 0; i < 8; ++i) {
1132 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1133 }
1134
1135 verts += 8 * vsize;
1136 for (int i = 0; i < 8; ++i) {
1137 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1138 }
1139
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001140 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001141 target->drawIndexed(kTriangles_PrimitiveType,
1142 0, 0, 16, aaStrokeRectIndexCount());
1143}
1144
reed@google.com20efde72011-05-09 17:00:02 +00001145/**
1146 * Returns true if the rects edges are integer-aligned.
1147 */
1148static bool isIRect(const GrRect& r) {
1149 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1150 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1151}
1152
bsalomon@google.com205d4602011-04-25 12:43:45 +00001153static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001154 const GrRect& rect,
1155 GrScalar width,
1156 const GrMatrix* matrix,
1157 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001158 GrRect* devRect,
1159 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001160 // we use a simple alpha ramp to do aa on axis-aligned rects
1161 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001162 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001163
bsalomon@google.coma3108262011-10-10 14:08:47 +00001164 // we are keeping around the "tweak the alpha" trick because
1165 // it is our only hope for the fixed-pipe implementation.
1166 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001167 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001168 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001169 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001170 if (target->getCaps().fSupportPerVertexCoverage) {
1171 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001172#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001173 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001174#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001175 return false;
1176 } else {
1177 *useVertexCoverage = true;
1178 }
1179 } else {
1180 GrPrintf("Rect AA dropped because no support for coverage.\n");
1181 return false;
1182 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001183 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001184 const GrDrawState& drawState = target->getDrawState();
1185 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001186 return false;
1187 }
1188
bsalomon@google.com471d4712011-08-23 15:45:25 +00001189 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001190 return false;
1191 }
1192
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001193 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001194 return false;
1195 }
1196
1197 if (NULL != matrix &&
1198 !matrix->preservesAxisAlignment()) {
1199 return false;
1200 }
1201
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001202 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001203 if (NULL != matrix) {
1204 combinedMatrix->preConcat(*matrix);
1205 GrAssert(combinedMatrix->preservesAxisAlignment());
1206 }
1207
1208 combinedMatrix->mapRect(devRect, rect);
1209 devRect->sort();
1210
1211 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001212 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001213 } else {
1214 return true;
1215 }
1216}
1217
bsalomon@google.com27847de2011-02-22 20:59:41 +00001218void GrContext::drawRect(const GrPaint& paint,
1219 const GrRect& rect,
1220 GrScalar width,
1221 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001222 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001223
1224 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001225 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001226
bsalomon@google.com205d4602011-04-25 12:43:45 +00001227 GrRect devRect = rect;
1228 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001229 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001230 bool needAA = paint.fAntiAlias &&
1231 !this->getRenderTarget()->isMultisampled();
1232 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1233 &combinedMatrix, &devRect,
1234 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001235
1236 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001237 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001238 if (width >= 0) {
1239 GrVec strokeSize;;
1240 if (width > 0) {
1241 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001242 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001243 strokeSize.setAbs(strokeSize);
1244 } else {
1245 strokeSize.set(GR_Scalar1, GR_Scalar1);
1246 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001247 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001248 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001249 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001250 }
1251 return;
1252 }
1253
bsalomon@google.com27847de2011-02-22 20:59:41 +00001254 if (width >= 0) {
1255 // TODO: consider making static vertex buffers for these cases.
1256 // Hairline could be done by just adding closing vertex to
1257 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001258 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1259
bsalomon@google.com27847de2011-02-22 20:59:41 +00001260 static const int worstCaseVertCount = 10;
1261 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1262
1263 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001264 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265 return;
1266 }
1267
1268 GrPrimitiveType primType;
1269 int vertCount;
1270 GrPoint* vertex = geo.positions();
1271
1272 if (width > 0) {
1273 vertCount = 10;
1274 primType = kTriangleStrip_PrimitiveType;
1275 setStrokeRectStrip(vertex, rect, width);
1276 } else {
1277 // hairline
1278 vertCount = 5;
1279 primType = kLineStrip_PrimitiveType;
1280 vertex[0].set(rect.fLeft, rect.fTop);
1281 vertex[1].set(rect.fRight, rect.fTop);
1282 vertex[2].set(rect.fRight, rect.fBottom);
1283 vertex[3].set(rect.fLeft, rect.fBottom);
1284 vertex[4].set(rect.fLeft, rect.fTop);
1285 }
1286
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001287 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001288 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001289 GrDrawState* drawState = target->drawState();
1290 avmr.set(drawState);
1291 drawState->preConcatViewMatrix(*matrix);
1292 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001293 }
1294
1295 target->drawNonIndexed(primType, 0, vertCount);
1296 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001297#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001298 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001299 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1300 if (NULL == sqVB) {
1301 GrPrintf("Failed to create static rect vb.\n");
1302 return;
1303 }
1304 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001305 GrDrawState* drawState = target->drawState();
1306 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001307 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001308 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001309 0, rect.height(), rect.fTop,
1310 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001311
1312 if (NULL != matrix) {
1313 m.postConcat(*matrix);
1314 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001315 drawState->preConcatViewMatrix(m);
1316 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001317
bsalomon@google.com27847de2011-02-22 20:59:41 +00001318 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001319#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001320 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001321#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001322 }
1323}
1324
1325void GrContext::drawRectToRect(const GrPaint& paint,
1326 const GrRect& dstRect,
1327 const GrRect& srcRect,
1328 const GrMatrix* dstMatrix,
1329 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001330 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001332 // srcRect refers to paint's first texture
1333 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001334 drawRect(paint, dstRect, -1, dstMatrix);
1335 return;
1336 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001337
bsalomon@google.com27847de2011-02-22 20:59:41 +00001338 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1339
1340#if GR_STATIC_RECT_VB
1341 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001342 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001343 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001344 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001345
1346 GrMatrix m;
1347
1348 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1349 0, dstRect.height(), dstRect.fTop,
1350 0, 0, GrMatrix::I()[8]);
1351 if (NULL != dstMatrix) {
1352 m.postConcat(*dstMatrix);
1353 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001354 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001355
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001356 // srcRect refers to first stage
1357 int otherStageMask = paint.getActiveStageMask() &
1358 (~(1 << GrPaint::kFirstTextureStage));
1359 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001360 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001361 }
1362
bsalomon@google.com27847de2011-02-22 20:59:41 +00001363 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1364 0, srcRect.height(), srcRect.fTop,
1365 0, 0, GrMatrix::I()[8]);
1366 if (NULL != srcMatrix) {
1367 m.postConcat(*srcMatrix);
1368 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001369 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001370
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001371 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1372 if (NULL == sqVB) {
1373 GrPrintf("Failed to create static rect vb.\n");
1374 return;
1375 }
1376 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1378#else
1379
1380 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001381#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001382 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001383#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001384 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1385#endif
1386
tomhudson@google.com93813632011-10-27 20:21:16 +00001387 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1388 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001389 srcRects[0] = &srcRect;
1390 srcMatrices[0] = srcMatrix;
1391
1392 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1393#endif
1394}
1395
1396void GrContext::drawVertices(const GrPaint& paint,
1397 GrPrimitiveType primitiveType,
1398 int vertexCount,
1399 const GrPoint positions[],
1400 const GrPoint texCoords[],
1401 const GrColor colors[],
1402 const uint16_t indices[],
1403 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001404 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405
1406 GrDrawTarget::AutoReleaseGeometry geo;
1407
1408 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1409
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001410 bool hasTexCoords[GrPaint::kTotalStages] = {
1411 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1412 0 // remaining stages use positions
1413 };
1414
1415 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416
1417 if (NULL != colors) {
1418 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001419 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001420 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001421
1422 if (sizeof(GrPoint) != vertexSize) {
1423 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001424 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001425 return;
1426 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001427 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001428 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001429 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1430 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001431 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001432 NULL,
1433 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001434 void* curVertex = geo.vertices();
1435
1436 for (int i = 0; i < vertexCount; ++i) {
1437 *((GrPoint*)curVertex) = positions[i];
1438
1439 if (texOffsets[0] > 0) {
1440 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1441 }
1442 if (colorOffset > 0) {
1443 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1444 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001445 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001446 }
1447 } else {
1448 target->setVertexSourceToArray(layout, positions, vertexCount);
1449 }
1450
bsalomon@google.com91958362011-06-13 17:58:13 +00001451 // we don't currently apply offscreen AA to this path. Need improved
1452 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001453
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001454 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001455 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001456 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001457 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001458 target->drawNonIndexed(primitiveType, 0, vertexCount);
1459 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460}
1461
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001462///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463
reed@google.com07f3ee12011-05-16 17:21:57 +00001464void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1465 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001467 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001468 if (GrIsFillInverted(fill)) {
1469 this->drawPaint(paint);
1470 }
1471 return;
1472 }
1473
bsalomon@google.com27847de2011-02-22 20:59:41 +00001474 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001475
bsalomon@google.com289533a2011-10-27 12:34:25 +00001476 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1477
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001478 // An Assumption here is that path renderer would use some form of tweaking
1479 // the src color (either the input alpha or in the frag shader) to implement
1480 // aa. If we have some future driver-mojo path AA that can do the right
1481 // thing WRT to the blend then we'll need some query on the PR.
1482 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001483#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001484 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001485#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001486 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001487 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001488
1489 bool doOSAA = false;
1490 GrPathRenderer* pr = NULL;
1491 if (prAA) {
1492 pr = this->getPathRenderer(path, fill, true);
1493 if (NULL == pr) {
1494 prAA = false;
1495 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1496 pr = this->getPathRenderer(path, fill, false);
1497 }
1498 } else {
1499 pr = this->getPathRenderer(path, fill, false);
1500 }
1501
bsalomon@google.com30085192011-08-19 15:42:31 +00001502 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001503#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001504 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001505#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001506 return;
1507 }
1508
bsalomon@google.com289533a2011-10-27 12:34:25 +00001509 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001510 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001511
bsalomon@google.com289533a2011-10-27 12:34:25 +00001512 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001513 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001514 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001515 // compute bounds as intersection of rt size, clip, and path
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001516 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001517 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001518 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001519 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001520 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001521 return;
1522 }
1523 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001524 GrRect pathBounds = path.getBounds();
1525 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001526 if (NULL != translate) {
1527 pathBounds.offset(*translate);
1528 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001529 target->getDrawState().getViewMatrix().mapRect(&pathBounds,
1530 pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001531 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001532 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001533 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001534 return;
1535 }
1536 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001537 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001538 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1539 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001540 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1541 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1542 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001543 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001544 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1545 }
1546 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001547 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001548 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001549 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1550 GrRect rect;
1551 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001552 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1553 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001554 target->drawSimpleRect(rect, NULL, stageMask);
1555 }
1556 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001557 rect.iset(clipIBounds.fLeft, bound.fTop,
1558 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001559 target->drawSimpleRect(rect, NULL, stageMask);
1560 }
1561 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001562 rect.iset(bound.fRight, bound.fTop,
1563 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001564 target->drawSimpleRect(rect, NULL, stageMask);
1565 }
1566 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001567 rect.iset(clipIBounds.fLeft, bound.fBottom,
1568 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001569 target->drawSimpleRect(rect, NULL, stageMask);
1570 }
1571 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001572 return;
1573 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001574 }
1575 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001576}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001577
bsalomon@google.com27847de2011-02-22 20:59:41 +00001578////////////////////////////////////////////////////////////////////////////////
1579
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001580void GrContext::flush(int flagsBitfield) {
1581 if (kDiscard_FlushBit & flagsBitfield) {
1582 fDrawBuffer->reset();
1583 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001584 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001585 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001586 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001587 fGpu->forceRenderTargetFlush();
1588 }
1589}
1590
1591void GrContext::flushText() {
1592 if (kText_DrawCategory == fLastDrawCategory) {
1593 flushDrawBuffer();
1594 }
1595}
1596
1597void GrContext::flushDrawBuffer() {
1598#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001599 if (fDrawBuffer) {
1600 fDrawBuffer->playback(fGpu);
1601 fDrawBuffer->reset();
1602 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001603#endif
1604}
1605
bsalomon@google.com6f379512011-11-16 20:36:03 +00001606void GrContext::internalWriteTexturePixels(GrTexture* texture,
1607 int left, int top,
1608 int width, int height,
1609 GrPixelConfig config,
1610 const void* buffer,
1611 size_t rowBytes,
1612 uint32_t flags) {
1613 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001614 ASSERT_OWNED_RESOURCE(texture);
1615
bsalomon@google.com6f379512011-11-16 20:36:03 +00001616 if (!(kDontFlush_PixelOpsFlag & flags)) {
1617 this->flush();
1618 }
1619 // TODO: use scratch texture to perform conversion
1620 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1621 GrPixelConfigIsUnpremultiplied(config)) {
1622 return;
1623 }
1624
1625 fGpu->writeTexturePixels(texture, left, top, width, height,
1626 config, buffer, rowBytes);
1627}
1628
1629bool GrContext::internalReadTexturePixels(GrTexture* texture,
1630 int left, int top,
1631 int width, int height,
1632 GrPixelConfig config,
1633 void* buffer,
1634 size_t rowBytes,
1635 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001636 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001637 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001638
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001639 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001640 GrRenderTarget* target = texture->asRenderTarget();
1641 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001642 return this->internalReadRenderTargetPixels(target,
1643 left, top, width, height,
1644 config, buffer, rowBytes,
1645 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001646 } else {
1647 return false;
1648 }
1649}
1650
bsalomon@google.com6f379512011-11-16 20:36:03 +00001651bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1652 int left, int top,
1653 int width, int height,
1654 GrPixelConfig config,
1655 void* buffer,
1656 size_t rowBytes,
1657 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001658 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001659 ASSERT_OWNED_RESOURCE(target);
1660
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001661 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001662 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001663 if (NULL == target) {
1664 return false;
1665 }
1666 }
1667
1668 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1669 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1670 // not supported at this time.
1671 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1672 !GrPixelConfigIsUnpremultiplied(config)) {
1673 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001674 }
1675
bsalomon@google.com6f379512011-11-16 20:36:03 +00001676 if (!(kDontFlush_PixelOpsFlag & flags)) {
1677 this->flush();
1678 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001679
1680 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001681 bool swapRAndB = NULL != src &&
1682 fGpu->preferredReadPixelsConfig(config) ==
1683 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001684
1685 bool flipY = NULL != src &&
1686 fGpu->readPixelsWillPayForYFlip(target, left, top,
1687 width, height, config,
1688 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001689 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1690 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001691
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001692 if (NULL == src && alphaConversion) {
1693 // we should fallback to cpu conversion here. This could happen when
1694 // we were given an external render target by the client that is not
1695 // also a texture (e.g. FBO 0 in GL)
1696 return false;
1697 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001698 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001699 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001700 if (flipY || swapRAndB || alphaConversion) {
1701 GrAssert(NULL != src);
1702 if (swapRAndB) {
1703 config = GrPixelConfigSwapRAndB(config);
1704 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001705 }
1706 // Make the scratch a render target because we don't have a robust
1707 // readTexturePixels as of yet (it calls this function).
1708 const GrTextureDesc desc = {
1709 kRenderTarget_GrTextureFlagBit,
1710 kNone_GrAALevel,
1711 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001712 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001713 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001714
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001715 // When a full readback is faster than a partial we could always make
1716 // the scratch exactly match the passed rect. However, if we see many
1717 // different size rectangles we will trash our texture cache and pay the
1718 // cost of creating and destroying many textures. So, we only request
1719 // an exact match when the caller is reading an entire RT.
1720 ScratchTexMatch match = kApprox_ScratchTexMatch;
1721 if (0 == left &&
1722 0 == top &&
1723 target->width() == width &&
1724 target->height() == height &&
1725 fGpu->fullReadPixelsIsFasterThanPartial()) {
1726 match = kExact_ScratchTexMatch;
1727 }
1728 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001729 GrTexture* texture = ast.texture();
1730 if (!texture) {
1731 return false;
1732 }
1733 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001734 GrAssert(NULL != target);
1735
1736 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001737 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001738 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001739 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001740
bsalomon@google.comc4364992011-11-07 15:54:49 +00001741 GrMatrix matrix;
1742 if (flipY) {
1743 matrix.setTranslate(SK_Scalar1 * left,
1744 SK_Scalar1 * (top + height));
1745 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1746 } else {
1747 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1748 }
1749 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001750 drawState->sampler(0)->reset(matrix);
1751 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001752 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001753 GrRect rect;
1754 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1755 fGpu->drawSimpleRect(rect, NULL, 0x1);
1756 left = 0;
1757 top = 0;
1758 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001759 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001760 left, top, width, height,
1761 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001762}
1763
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001764void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1765 if (NULL == src || NULL == dst) {
1766 return;
1767 }
1768 ASSERT_OWNED_RESOURCE(src);
1769
1770 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001771 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001772 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001773 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001774 GrMatrix sampleM;
1775 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001776 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001777 drawState->sampler(0)->reset(sampleM);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001778 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1779 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1780}
1781
bsalomon@google.com6f379512011-11-16 20:36:03 +00001782void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1783 int left, int top,
1784 int width, int height,
1785 GrPixelConfig config,
1786 const void* buffer,
1787 size_t rowBytes,
1788 uint32_t flags) {
1789 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001790 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001791
1792 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001793 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001794 if (NULL == target) {
1795 return;
1796 }
1797 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001798
1799 // TODO: when underlying api has a direct way to do this we should use it
1800 // (e.g. glDrawPixels on desktop GL).
1801
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001802 // If the RT is also a texture and we don't have to do PM/UPM conversion
1803 // then take the texture path, which we expect to be at least as fast or
1804 // faster since it doesn't use an intermediate texture as we do below.
1805
1806#if !GR_MAC_BUILD
1807 // At least some drivers on the Mac get confused when glTexImage2D is called
1808 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1809 // determine what OS versions and/or HW is affected.
1810 if (NULL != target->asTexture() &&
1811 GrPixelConfigIsUnpremultiplied(target->config()) ==
1812 GrPixelConfigIsUnpremultiplied(config)) {
1813
1814 this->internalWriteTexturePixels(target->asTexture(),
1815 left, top, width, height,
1816 config, buffer, rowBytes, flags);
1817 return;
1818 }
1819#endif
1820
1821 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1822 GrPixelConfigSwapRAndB(config);
1823 if (swapRAndB) {
1824 config = GrPixelConfigSwapRAndB(config);
1825 }
1826
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001827 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001828 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001829 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001830 GrAutoScratchTexture ast(this, desc);
1831 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001832 if (NULL == texture) {
1833 return;
1834 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001835 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1836 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001837
bsalomon@google.com27847de2011-02-22 20:59:41 +00001838 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001839 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001840 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001841
1842 GrMatrix matrix;
1843 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001844 drawState->setViewMatrix(matrix);
1845 drawState->setRenderTarget(target);
1846 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001847
bsalomon@google.com5c638652011-07-18 19:31:59 +00001848 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001849 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1850 GrSamplerState::kNearest_Filter,
1851 matrix);
1852 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001853
1854 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1855 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001856 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001857 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1858 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001859 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001860 return;
1861 }
1862 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1863 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1864}
1865////////////////////////////////////////////////////////////////////////////////
1866
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001867void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001868 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001869
1870 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1871 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001872 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001873 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001874 if (paint.getTexture(i)) {
1875 *drawState->sampler(s) = paint.getTextureSampler(i);
1876 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001877 }
1878
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001879 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001880
1881 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1882 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001883 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001884 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001885 if (paint.getMask(i)) {
1886 *drawState->sampler(s) = paint.getMaskSampler(i);
1887 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001888 }
1889
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001890 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001891
1892 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001893 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001894 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001895 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001896 }
1897 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001898 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001899 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001900 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001901 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001902 if (paint.fColorMatrixEnabled) {
1903 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
1904 } else {
1905 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
1906 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001907 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001908 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001909 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001910
1911 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1912 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1913 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001914}
1915
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001916GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001917 DrawCategory category) {
1918 if (category != fLastDrawCategory) {
1919 flushDrawBuffer();
1920 fLastDrawCategory = category;
1921 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001922 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001923 GrDrawTarget* target = fGpu;
1924 switch (category) {
1925 case kText_DrawCategory:
1926#if DEFER_TEXT_RENDERING
1927 target = fDrawBuffer;
1928 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1929#else
1930 target = fGpu;
1931#endif
1932 break;
1933 case kUnbuffered_DrawCategory:
1934 target = fGpu;
1935 break;
1936 case kBuffered_DrawCategory:
1937 target = fDrawBuffer;
1938 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1939 break;
1940 }
1941 return target;
1942}
1943
bsalomon@google.com289533a2011-10-27 12:34:25 +00001944GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1945 GrPathFill fill,
1946 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001947 if (NULL == fPathRendererChain) {
1948 fPathRendererChain =
1949 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1950 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001951 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1952 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001953}
1954
bsalomon@google.com27847de2011-02-22 20:59:41 +00001955////////////////////////////////////////////////////////////////////////////////
1956
bsalomon@google.com27847de2011-02-22 20:59:41 +00001957void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001958 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001959 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001960 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001961}
1962
1963GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001964 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001965}
1966
1967const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001968 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001969}
1970
1971const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001972 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001973}
1974
1975void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001976 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001977}
1978
1979void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001980 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001981}
1982
1983static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1984 intptr_t mask = 1 << shift;
1985 if (pred) {
1986 bits |= mask;
1987 } else {
1988 bits &= ~mask;
1989 }
1990 return bits;
1991}
1992
1993void GrContext::resetStats() {
1994 fGpu->resetStats();
1995}
1996
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001997const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001998 return fGpu->getStats();
1999}
2000
2001void GrContext::printStats() const {
2002 fGpu->printStats();
2003}
2004
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002005GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002006 fGpu = gpu;
2007 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002008 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002009
bsalomon@google.com30085192011-08-19 15:42:31 +00002010 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002011
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002012 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2013 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002014 fFontCache = new GrFontCache(fGpu);
2015
2016 fLastDrawCategory = kUnbuffered_DrawCategory;
2017
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002018 fDrawBuffer = NULL;
2019 fDrawBufferVBAllocPool = NULL;
2020 fDrawBufferIBAllocPool = NULL;
2021
bsalomon@google.com205d4602011-04-25 12:43:45 +00002022 fAAFillRectIndexBuffer = NULL;
2023 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002024
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002025 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2026 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002027 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2028 }
2029 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002030
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002031 this->setupDrawBuffer();
2032}
2033
2034void GrContext::setupDrawBuffer() {
2035
2036 GrAssert(NULL == fDrawBuffer);
2037 GrAssert(NULL == fDrawBufferVBAllocPool);
2038 GrAssert(NULL == fDrawBufferIBAllocPool);
2039
bsalomon@google.com27847de2011-02-22 20:59:41 +00002040#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002041 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002042 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002043 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2044 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002045 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002046 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002047 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002048 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2049
bsalomon@google.com471d4712011-08-23 15:45:25 +00002050 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2051 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002052 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002053#endif
2054
2055#if BATCH_RECT_TO_RECT
2056 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2057#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002058}
2059
bsalomon@google.com27847de2011-02-22 20:59:41 +00002060GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2061 GrDrawTarget* target;
2062#if DEFER_TEXT_RENDERING
2063 target = prepareToDraw(paint, kText_DrawCategory);
2064#else
2065 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2066#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002067 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002068 return target;
2069}
2070
2071const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2072 return fGpu->getQuadIndexBuffer();
2073}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002074
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002075void GrContext::convolveInX(GrTexture* texture,
2076 const SkRect& rect,
2077 const float* kernel,
2078 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002079 ASSERT_OWNED_RESOURCE(texture);
2080
bsalomon@google.com99621082011-11-15 16:47:16 +00002081 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002082 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2083}
2084
2085void GrContext::convolveInY(GrTexture* texture,
2086 const SkRect& rect,
2087 const float* kernel,
2088 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002089 ASSERT_OWNED_RESOURCE(texture);
2090
bsalomon@google.com99621082011-11-15 16:47:16 +00002091 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002092 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2093}
2094
2095void GrContext::convolve(GrTexture* texture,
2096 const SkRect& rect,
2097 float imageIncrement[2],
2098 const float* kernel,
2099 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002100 ASSERT_OWNED_RESOURCE(texture);
2101
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002102 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002103 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002104 GrMatrix sampleM;
2105 sampleM.setIDiv(texture->width(), texture->height());
2106 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2107 GrSamplerState::kConvolution_Filter,
2108 sampleM);
2109 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2110 kernel,
2111 imageIncrement);
2112
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002113 drawState->setViewMatrix(GrMatrix::I());
2114 drawState->setTexture(0, texture);
2115 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002116 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002117 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2118}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002119
2120///////////////////////////////////////////////////////////////////////////////