blob: 151575d78eb183e3220b2906a02995b0c8912011 [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.com50398bf2011-07-26 20:45:30 +0000724 GrAssert(NULL == record->fOffscreen0.texture());
725 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000726 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000727
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000728 int boundW = boundRect.width();
729 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000730
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000731 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000732
733 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
734 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
735
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000736 if (requireStencil) {
737 desc.fFlags = kRenderTarget_GrTextureFlagBit;
738 } else {
739 desc.fFlags = kRenderTarget_GrTextureFlagBit |
740 kNoStencil_GrTextureFlagBit;
741 }
742
bsalomon@google.comc4364992011-11-07 15:54:49 +0000743 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000744
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000745 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000746 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000747 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000748 desc.fAALevel = kMed_GrAALevel;
749 } else {
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000750 record->fDownsample = OffscreenRecord::k4x4SinglePass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000751 record->fScale = OFFSCREEN_SSAA_SCALE;
752 // both downsample paths assume this
753 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000754 desc.fAALevel = kNone_GrAALevel;
755 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000756
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000757 desc.fWidth *= record->fScale;
758 desc.fHeight *= record->fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000759 record->fOffscreen.set(this, desc);
760 if (NULL == record->fOffscreen.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000761 return false;
762 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000763 // the approximate lookup might have given us some slop space, might as well
764 // use it when computing the tiles size.
765 // these are scale values, will adjust after considering
766 // the possible second offscreen.
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000767 record->fTileSizeX = record->fOffscreen.texture()->width();
768 record->fTileSizeY = record->fOffscreen.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000769
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000770 record->fTileSizeX /= record->fScale;
771 record->fTileSizeY /= record->fScale;
772
773 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
774 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
775
tomhudson@google.com237a4612011-07-19 15:44:00 +0000776 record->fClip = target->getClip();
777
bsalomon@google.com91958362011-06-13 17:58:13 +0000778 target->saveCurrentDrawState(&record->fSavedState);
779 return true;
780}
781
782void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
783 const GrIRect& boundRect,
784 int tileX, int tileY,
785 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000786
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000787 GrRenderTarget* offRT = record->fOffscreen.texture()->asRenderTarget();
788 GrAssert(NULL != offRT);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000789
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000790 GrPaint tempPaint;
791 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000792 this->setPaint(tempPaint, target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000793 GrDrawState* drawState = target->drawState();
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000794 drawState->setRenderTarget(offRT);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000795#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com337af172012-01-11 16:00:42 +0000796 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000797#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000798
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000799 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000800 int left = boundRect.fLeft + tileX * record->fTileSizeX;
801 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000802 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000803 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000804 GrMatrix scaleM;
805 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000806 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000807
bsalomon@google.com91958362011-06-13 17:58:13 +0000808 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000809 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000810 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000811 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000812 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
813 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000814 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000815#if 0
816 // visualize tile boundaries by setting edges of offscreen to white
817 // and interior to tranparent. black.
818 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000819
bsalomon@google.com91958362011-06-13 17:58:13 +0000820 static const int gOffset = 2;
821 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
822 record->fScale * w - gOffset,
823 record->fScale * h - gOffset);
824 target->clear(&clear2, 0x0);
825#else
826 target->clear(&clear, 0x0);
827#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000828}
829
bsalomon@google.com91958362011-06-13 17:58:13 +0000830void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000831 const GrPaint& paint,
832 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000833 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000834 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000835 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000836 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000837 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000838 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000839 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
840 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000841 tileRect.fRight = (tileX == record->fTileCountX-1) ?
842 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000843 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000844 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
845 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000846 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000847
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000848 GrSamplerState::Filter filter;
849 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
850 filter = GrSamplerState::k4x4Downsample_Filter;
851 } else {
852 filter = GrSamplerState::kBilinear_Filter;
853 }
854
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000855 GrTexture* src = record->fOffscreen.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000856 int scale;
857
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000858 enum {
859 kOffscreenStage = GrPaint::kTotalStages,
860 };
861
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000862 GrDrawState* drawState = target->drawState();
863
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000864 if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000865 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000866 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000867 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000868 } else {
869 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
870 record->fDownsample);
871 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 }
873
bsalomon@google.com91958362011-06-13 17:58:13 +0000874 // setup for draw back to main RT, we use the original
875 // draw state setup by the caller plus an additional coverage
876 // stage to handle the AA resolve. Also, we use an identity
877 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000878 int stageMask = paint.getActiveStageMask();
879
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000880 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000881 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000882
883 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000884 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000885 if (drawState->getViewInverse(&invVM)) {
886 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000887 }
888 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000889 // This is important when tiling, otherwise second tile's
890 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000891 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000892
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000893 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000894 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
895 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000896 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
897 scale * GR_Scalar1 / src->height());
898 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
899 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000900
reed@google.com20efde72011-05-09 17:00:02 +0000901 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000902 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000903 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000904 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000905}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000906
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000907void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
908 GrPathRenderer* pr,
909 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000910 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000911}
912
913////////////////////////////////////////////////////////////////////////////////
914
bsalomon@google.com27847de2011-02-22 20:59:41 +0000915/* create a triangle strip that strokes the specified triangle. There are 8
916 unique vertices, but we repreat the last 2 to close up. Alternatively we
917 could use an indices array, and then only send 8 verts, but not sure that
918 would be faster.
919 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000920static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000921 GrScalar width) {
922 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000923 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000924
925 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
926 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
927 verts[2].set(rect.fRight - rad, rect.fTop + rad);
928 verts[3].set(rect.fRight + rad, rect.fTop - rad);
929 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
930 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
931 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
932 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
933 verts[8] = verts[0];
934 verts[9] = verts[1];
935}
936
bsalomon@google.com205d4602011-04-25 12:43:45 +0000937static void setInsetFan(GrPoint* pts, size_t stride,
938 const GrRect& r, GrScalar dx, GrScalar dy) {
939 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
940}
941
942static const uint16_t gFillAARectIdx[] = {
943 0, 1, 5, 5, 4, 0,
944 1, 2, 6, 6, 5, 1,
945 2, 3, 7, 7, 6, 2,
946 3, 0, 4, 4, 7, 3,
947 4, 5, 6, 6, 7, 4,
948};
949
950int GrContext::aaFillRectIndexCount() const {
951 return GR_ARRAY_COUNT(gFillAARectIdx);
952}
953
954GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
955 if (NULL == fAAFillRectIndexBuffer) {
956 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
957 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000958 if (NULL != fAAFillRectIndexBuffer) {
959 #if GR_DEBUG
960 bool updated =
961 #endif
962 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
963 sizeof(gFillAARectIdx));
964 GR_DEBUGASSERT(updated);
965 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000966 }
967 return fAAFillRectIndexBuffer;
968}
969
970static const uint16_t gStrokeAARectIdx[] = {
971 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
972 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
973 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
974 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
975
976 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
977 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
978 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
979 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
980
981 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
982 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
983 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
984 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
985};
986
987int GrContext::aaStrokeRectIndexCount() const {
988 return GR_ARRAY_COUNT(gStrokeAARectIdx);
989}
990
991GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
992 if (NULL == fAAStrokeRectIndexBuffer) {
993 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
994 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000995 if (NULL != fAAStrokeRectIndexBuffer) {
996 #if GR_DEBUG
997 bool updated =
998 #endif
999 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1000 sizeof(gStrokeAARectIdx));
1001 GR_DEBUGASSERT(updated);
1002 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001003 }
1004 return fAAStrokeRectIndexBuffer;
1005}
1006
bsalomon@google.coma3108262011-10-10 14:08:47 +00001007static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1008 bool useCoverage) {
1009 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001010 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001011 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001012 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1013 }
1014 }
1015 if (useCoverage) {
1016 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1017 } else {
1018 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1019 }
1020 return layout;
1021}
1022
bsalomon@google.com205d4602011-04-25 12:43:45 +00001023void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001024 const GrRect& devRect,
1025 bool useVertexCoverage) {
1026 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001027
1028 size_t vsize = GrDrawTarget::VertexSize(layout);
1029
1030 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001031 if (!geo.succeeded()) {
1032 GrPrintf("Failed to get space for vertices!\n");
1033 return;
1034 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001035 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1036 if (NULL == indexBuffer) {
1037 GrPrintf("Failed to create index buffer!\n");
1038 return;
1039 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001040
1041 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1042
1043 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1044 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1045
1046 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1047 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1048
1049 verts += sizeof(GrPoint);
1050 for (int i = 0; i < 4; ++i) {
1051 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1052 }
1053
bsalomon@google.coma3108262011-10-10 14:08:47 +00001054 GrColor innerColor;
1055 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001056 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001057 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001058 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001059 }
1060
bsalomon@google.com205d4602011-04-25 12:43:45 +00001061 verts += 4 * vsize;
1062 for (int i = 0; i < 4; ++i) {
1063 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1064 }
1065
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001066 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001067
1068 target->drawIndexed(kTriangles_PrimitiveType, 0,
1069 0, 8, this->aaFillRectIndexCount());
1070}
1071
bsalomon@google.coma3108262011-10-10 14:08:47 +00001072void GrContext::strokeAARect(GrDrawTarget* target,
1073 const GrRect& devRect,
1074 const GrVec& devStrokeSize,
1075 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001076 const GrScalar& dx = devStrokeSize.fX;
1077 const GrScalar& dy = devStrokeSize.fY;
1078 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1079 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1080
bsalomon@google.com205d4602011-04-25 12:43:45 +00001081 GrScalar spare;
1082 {
1083 GrScalar w = devRect.width() - dx;
1084 GrScalar h = devRect.height() - dy;
1085 spare = GrMin(w, h);
1086 }
1087
1088 if (spare <= 0) {
1089 GrRect r(devRect);
1090 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001091 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001092 return;
1093 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001094 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001095 size_t vsize = GrDrawTarget::VertexSize(layout);
1096
1097 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001098 if (!geo.succeeded()) {
1099 GrPrintf("Failed to get space for vertices!\n");
1100 return;
1101 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001102 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1103 if (NULL == indexBuffer) {
1104 GrPrintf("Failed to create index buffer!\n");
1105 return;
1106 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001107
1108 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1109
1110 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1111 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1112 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1113 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1114
1115 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1116 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1117 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1118 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1119
1120 verts += sizeof(GrPoint);
1121 for (int i = 0; i < 4; ++i) {
1122 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1123 }
1124
bsalomon@google.coma3108262011-10-10 14:08:47 +00001125 GrColor innerColor;
1126 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001127 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001128 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001129 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001130 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001131 verts += 4 * vsize;
1132 for (int i = 0; i < 8; ++i) {
1133 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1134 }
1135
1136 verts += 8 * vsize;
1137 for (int i = 0; i < 8; ++i) {
1138 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1139 }
1140
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001141 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001142 target->drawIndexed(kTriangles_PrimitiveType,
1143 0, 0, 16, aaStrokeRectIndexCount());
1144}
1145
reed@google.com20efde72011-05-09 17:00:02 +00001146/**
1147 * Returns true if the rects edges are integer-aligned.
1148 */
1149static bool isIRect(const GrRect& r) {
1150 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1151 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1152}
1153
bsalomon@google.com205d4602011-04-25 12:43:45 +00001154static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001155 const GrRect& rect,
1156 GrScalar width,
1157 const GrMatrix* matrix,
1158 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001159 GrRect* devRect,
1160 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001161 // we use a simple alpha ramp to do aa on axis-aligned rects
1162 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001163 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001164
bsalomon@google.coma3108262011-10-10 14:08:47 +00001165 // we are keeping around the "tweak the alpha" trick because
1166 // it is our only hope for the fixed-pipe implementation.
1167 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001168 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001169 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001170 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001171 if (target->getCaps().fSupportPerVertexCoverage) {
1172 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001173#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001174 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001175#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001176 return false;
1177 } else {
1178 *useVertexCoverage = true;
1179 }
1180 } else {
1181 GrPrintf("Rect AA dropped because no support for coverage.\n");
1182 return false;
1183 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001184 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001185 const GrDrawState& drawState = target->getDrawState();
1186 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001187 return false;
1188 }
1189
bsalomon@google.com471d4712011-08-23 15:45:25 +00001190 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001191 return false;
1192 }
1193
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001194 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001195 return false;
1196 }
1197
1198 if (NULL != matrix &&
1199 !matrix->preservesAxisAlignment()) {
1200 return false;
1201 }
1202
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001203 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001204 if (NULL != matrix) {
1205 combinedMatrix->preConcat(*matrix);
1206 GrAssert(combinedMatrix->preservesAxisAlignment());
1207 }
1208
1209 combinedMatrix->mapRect(devRect, rect);
1210 devRect->sort();
1211
1212 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001213 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001214 } else {
1215 return true;
1216 }
1217}
1218
bsalomon@google.com27847de2011-02-22 20:59:41 +00001219void GrContext::drawRect(const GrPaint& paint,
1220 const GrRect& rect,
1221 GrScalar width,
1222 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001223 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001224
1225 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001226 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227
bsalomon@google.com205d4602011-04-25 12:43:45 +00001228 GrRect devRect = rect;
1229 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001230 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001231 bool needAA = paint.fAntiAlias &&
1232 !this->getRenderTarget()->isMultisampled();
1233 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1234 &combinedMatrix, &devRect,
1235 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001236
1237 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001238 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001239 if (width >= 0) {
1240 GrVec strokeSize;;
1241 if (width > 0) {
1242 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001243 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001244 strokeSize.setAbs(strokeSize);
1245 } else {
1246 strokeSize.set(GR_Scalar1, GR_Scalar1);
1247 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001248 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001249 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001250 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001251 }
1252 return;
1253 }
1254
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255 if (width >= 0) {
1256 // TODO: consider making static vertex buffers for these cases.
1257 // Hairline could be done by just adding closing vertex to
1258 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001259 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1260
bsalomon@google.com27847de2011-02-22 20:59:41 +00001261 static const int worstCaseVertCount = 10;
1262 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1263
1264 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001265 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001266 return;
1267 }
1268
1269 GrPrimitiveType primType;
1270 int vertCount;
1271 GrPoint* vertex = geo.positions();
1272
1273 if (width > 0) {
1274 vertCount = 10;
1275 primType = kTriangleStrip_PrimitiveType;
1276 setStrokeRectStrip(vertex, rect, width);
1277 } else {
1278 // hairline
1279 vertCount = 5;
1280 primType = kLineStrip_PrimitiveType;
1281 vertex[0].set(rect.fLeft, rect.fTop);
1282 vertex[1].set(rect.fRight, rect.fTop);
1283 vertex[2].set(rect.fRight, rect.fBottom);
1284 vertex[3].set(rect.fLeft, rect.fBottom);
1285 vertex[4].set(rect.fLeft, rect.fTop);
1286 }
1287
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001288 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001289 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001290 GrDrawState* drawState = target->drawState();
1291 avmr.set(drawState);
1292 drawState->preConcatViewMatrix(*matrix);
1293 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001294 }
1295
1296 target->drawNonIndexed(primType, 0, vertCount);
1297 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001298#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001299 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001300 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1301 if (NULL == sqVB) {
1302 GrPrintf("Failed to create static rect vb.\n");
1303 return;
1304 }
1305 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001306 GrDrawState* drawState = target->drawState();
1307 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001308 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001309 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001310 0, rect.height(), rect.fTop,
1311 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001312
1313 if (NULL != matrix) {
1314 m.postConcat(*matrix);
1315 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001316 drawState->preConcatViewMatrix(m);
1317 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001318
bsalomon@google.com27847de2011-02-22 20:59:41 +00001319 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001320#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001321 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001322#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001323 }
1324}
1325
1326void GrContext::drawRectToRect(const GrPaint& paint,
1327 const GrRect& dstRect,
1328 const GrRect& srcRect,
1329 const GrMatrix* dstMatrix,
1330 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001331 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001332
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001333 // srcRect refers to paint's first texture
1334 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001335 drawRect(paint, dstRect, -1, dstMatrix);
1336 return;
1337 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001338
bsalomon@google.com27847de2011-02-22 20:59:41 +00001339 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1340
1341#if GR_STATIC_RECT_VB
1342 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001343 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001344 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001345 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001346
1347 GrMatrix m;
1348
1349 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1350 0, dstRect.height(), dstRect.fTop,
1351 0, 0, GrMatrix::I()[8]);
1352 if (NULL != dstMatrix) {
1353 m.postConcat(*dstMatrix);
1354 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001355 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001356
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001357 // srcRect refers to first stage
1358 int otherStageMask = paint.getActiveStageMask() &
1359 (~(1 << GrPaint::kFirstTextureStage));
1360 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001361 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001362 }
1363
bsalomon@google.com27847de2011-02-22 20:59:41 +00001364 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1365 0, srcRect.height(), srcRect.fTop,
1366 0, 0, GrMatrix::I()[8]);
1367 if (NULL != srcMatrix) {
1368 m.postConcat(*srcMatrix);
1369 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001370 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001371
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001372 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1373 if (NULL == sqVB) {
1374 GrPrintf("Failed to create static rect vb.\n");
1375 return;
1376 }
1377 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001378 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1379#else
1380
1381 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001382#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001383 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001384#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001385 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1386#endif
1387
tomhudson@google.com93813632011-10-27 20:21:16 +00001388 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1389 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001390 srcRects[0] = &srcRect;
1391 srcMatrices[0] = srcMatrix;
1392
1393 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1394#endif
1395}
1396
1397void GrContext::drawVertices(const GrPaint& paint,
1398 GrPrimitiveType primitiveType,
1399 int vertexCount,
1400 const GrPoint positions[],
1401 const GrPoint texCoords[],
1402 const GrColor colors[],
1403 const uint16_t indices[],
1404 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001405 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001406
1407 GrDrawTarget::AutoReleaseGeometry geo;
1408
1409 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1410
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001411 bool hasTexCoords[GrPaint::kTotalStages] = {
1412 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1413 0 // remaining stages use positions
1414 };
1415
1416 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417
1418 if (NULL != colors) {
1419 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001421 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001422
1423 if (sizeof(GrPoint) != vertexSize) {
1424 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001425 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001426 return;
1427 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001428 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001429 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001430 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1431 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001432 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001433 NULL,
1434 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001435 void* curVertex = geo.vertices();
1436
1437 for (int i = 0; i < vertexCount; ++i) {
1438 *((GrPoint*)curVertex) = positions[i];
1439
1440 if (texOffsets[0] > 0) {
1441 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1442 }
1443 if (colorOffset > 0) {
1444 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1445 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001446 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001447 }
1448 } else {
1449 target->setVertexSourceToArray(layout, positions, vertexCount);
1450 }
1451
bsalomon@google.com91958362011-06-13 17:58:13 +00001452 // we don't currently apply offscreen AA to this path. Need improved
1453 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001454
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001455 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001456 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001457 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001458 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001459 target->drawNonIndexed(primitiveType, 0, vertexCount);
1460 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001461}
1462
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001463///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001464
reed@google.com07f3ee12011-05-16 17:21:57 +00001465void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1466 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001467
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001468 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001469 if (GrIsFillInverted(fill)) {
1470 this->drawPaint(paint);
1471 }
1472 return;
1473 }
1474
bsalomon@google.com27847de2011-02-22 20:59:41 +00001475 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001476
bsalomon@google.com289533a2011-10-27 12:34:25 +00001477 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1478
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001479 // An Assumption here is that path renderer would use some form of tweaking
1480 // the src color (either the input alpha or in the frag shader) to implement
1481 // aa. If we have some future driver-mojo path AA that can do the right
1482 // thing WRT to the blend then we'll need some query on the PR.
1483 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001484#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001485 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001486#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001487 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001488 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001489
1490 bool doOSAA = false;
1491 GrPathRenderer* pr = NULL;
1492 if (prAA) {
1493 pr = this->getPathRenderer(path, fill, true);
1494 if (NULL == pr) {
1495 prAA = false;
1496 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1497 pr = this->getPathRenderer(path, fill, false);
1498 }
1499 } else {
1500 pr = this->getPathRenderer(path, fill, false);
1501 }
1502
bsalomon@google.com30085192011-08-19 15:42:31 +00001503 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001504#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001505 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001506#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001507 return;
1508 }
1509
bsalomon@google.com289533a2011-10-27 12:34:25 +00001510 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001511 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001512
bsalomon@google.com289533a2011-10-27 12:34:25 +00001513 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001514 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001515 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001516 // compute bounds as intersection of rt size, clip, and path
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001517 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001518 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001519 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001520 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001521 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001522 return;
1523 }
1524 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001525 GrRect pathBounds = path.getBounds();
1526 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001527 if (NULL != translate) {
1528 pathBounds.offset(*translate);
1529 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001530 target->getDrawState().getViewMatrix().mapRect(&pathBounds,
1531 pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001532 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001533 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001534 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001535 return;
1536 }
1537 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001538 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001539 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1540 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001541 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1542 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1543 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001544 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001545 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1546 }
1547 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001548 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001549 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001550 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1551 GrRect rect;
1552 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001553 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1554 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001555 target->drawSimpleRect(rect, NULL, stageMask);
1556 }
1557 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001558 rect.iset(clipIBounds.fLeft, bound.fTop,
1559 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001560 target->drawSimpleRect(rect, NULL, stageMask);
1561 }
1562 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001563 rect.iset(bound.fRight, bound.fTop,
1564 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001565 target->drawSimpleRect(rect, NULL, stageMask);
1566 }
1567 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001568 rect.iset(clipIBounds.fLeft, bound.fBottom,
1569 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001570 target->drawSimpleRect(rect, NULL, stageMask);
1571 }
1572 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001573 return;
1574 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001575 }
1576 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001577}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001578
bsalomon@google.com27847de2011-02-22 20:59:41 +00001579////////////////////////////////////////////////////////////////////////////////
1580
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001581void GrContext::flush(int flagsBitfield) {
1582 if (kDiscard_FlushBit & flagsBitfield) {
1583 fDrawBuffer->reset();
1584 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001585 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001586 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001587 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001588 fGpu->forceRenderTargetFlush();
1589 }
1590}
1591
1592void GrContext::flushText() {
1593 if (kText_DrawCategory == fLastDrawCategory) {
1594 flushDrawBuffer();
1595 }
1596}
1597
1598void GrContext::flushDrawBuffer() {
1599#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001600 if (fDrawBuffer) {
1601 fDrawBuffer->playback(fGpu);
1602 fDrawBuffer->reset();
1603 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001604#endif
1605}
1606
bsalomon@google.com6f379512011-11-16 20:36:03 +00001607void GrContext::internalWriteTexturePixels(GrTexture* texture,
1608 int left, int top,
1609 int width, int height,
1610 GrPixelConfig config,
1611 const void* buffer,
1612 size_t rowBytes,
1613 uint32_t flags) {
1614 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001615 ASSERT_OWNED_RESOURCE(texture);
1616
bsalomon@google.com6f379512011-11-16 20:36:03 +00001617 if (!(kDontFlush_PixelOpsFlag & flags)) {
1618 this->flush();
1619 }
1620 // TODO: use scratch texture to perform conversion
1621 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1622 GrPixelConfigIsUnpremultiplied(config)) {
1623 return;
1624 }
1625
1626 fGpu->writeTexturePixels(texture, left, top, width, height,
1627 config, buffer, rowBytes);
1628}
1629
1630bool GrContext::internalReadTexturePixels(GrTexture* texture,
1631 int left, int top,
1632 int width, int height,
1633 GrPixelConfig config,
1634 void* buffer,
1635 size_t rowBytes,
1636 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001637 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001638 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001639
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001640 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001641 GrRenderTarget* target = texture->asRenderTarget();
1642 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001643 return this->internalReadRenderTargetPixels(target,
1644 left, top, width, height,
1645 config, buffer, rowBytes,
1646 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001647 } else {
1648 return false;
1649 }
1650}
1651
bsalomon@google.com6f379512011-11-16 20:36:03 +00001652bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1653 int left, int top,
1654 int width, int height,
1655 GrPixelConfig config,
1656 void* buffer,
1657 size_t rowBytes,
1658 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001659 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001660 ASSERT_OWNED_RESOURCE(target);
1661
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001662 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001663 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001664 if (NULL == target) {
1665 return false;
1666 }
1667 }
1668
1669 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1670 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1671 // not supported at this time.
1672 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1673 !GrPixelConfigIsUnpremultiplied(config)) {
1674 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001675 }
1676
bsalomon@google.com6f379512011-11-16 20:36:03 +00001677 if (!(kDontFlush_PixelOpsFlag & flags)) {
1678 this->flush();
1679 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001680
1681 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001682 bool swapRAndB = NULL != src &&
1683 fGpu->preferredReadPixelsConfig(config) ==
1684 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001685
1686 bool flipY = NULL != src &&
1687 fGpu->readPixelsWillPayForYFlip(target, left, top,
1688 width, height, config,
1689 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001690 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1691 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001692
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001693 if (NULL == src && alphaConversion) {
1694 // we should fallback to cpu conversion here. This could happen when
1695 // we were given an external render target by the client that is not
1696 // also a texture (e.g. FBO 0 in GL)
1697 return false;
1698 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001699 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001700 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001701 if (flipY || swapRAndB || alphaConversion) {
1702 GrAssert(NULL != src);
1703 if (swapRAndB) {
1704 config = GrPixelConfigSwapRAndB(config);
1705 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001706 }
1707 // Make the scratch a render target because we don't have a robust
1708 // readTexturePixels as of yet (it calls this function).
1709 const GrTextureDesc desc = {
1710 kRenderTarget_GrTextureFlagBit,
1711 kNone_GrAALevel,
1712 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001713 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001714 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001715
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001716 // When a full readback is faster than a partial we could always make
1717 // the scratch exactly match the passed rect. However, if we see many
1718 // different size rectangles we will trash our texture cache and pay the
1719 // cost of creating and destroying many textures. So, we only request
1720 // an exact match when the caller is reading an entire RT.
1721 ScratchTexMatch match = kApprox_ScratchTexMatch;
1722 if (0 == left &&
1723 0 == top &&
1724 target->width() == width &&
1725 target->height() == height &&
1726 fGpu->fullReadPixelsIsFasterThanPartial()) {
1727 match = kExact_ScratchTexMatch;
1728 }
1729 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001730 GrTexture* texture = ast.texture();
1731 if (!texture) {
1732 return false;
1733 }
1734 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001735 GrAssert(NULL != target);
1736
1737 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001738 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001739 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001740 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001741
bsalomon@google.comc4364992011-11-07 15:54:49 +00001742 GrMatrix matrix;
1743 if (flipY) {
1744 matrix.setTranslate(SK_Scalar1 * left,
1745 SK_Scalar1 * (top + height));
1746 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1747 } else {
1748 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1749 }
1750 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001751 drawState->sampler(0)->reset(matrix);
1752 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001753 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001754 GrRect rect;
1755 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1756 fGpu->drawSimpleRect(rect, NULL, 0x1);
1757 left = 0;
1758 top = 0;
1759 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001760 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001761 left, top, width, height,
1762 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001763}
1764
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001765void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1766 if (NULL == src || NULL == dst) {
1767 return;
1768 }
1769 ASSERT_OWNED_RESOURCE(src);
1770
1771 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001772 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001773 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001774 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001775 GrMatrix sampleM;
1776 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001777 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001778 drawState->sampler(0)->reset(sampleM);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001779 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1780 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1781}
1782
bsalomon@google.com6f379512011-11-16 20:36:03 +00001783void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1784 int left, int top,
1785 int width, int height,
1786 GrPixelConfig config,
1787 const void* buffer,
1788 size_t rowBytes,
1789 uint32_t flags) {
1790 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001791 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001792
1793 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001794 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001795 if (NULL == target) {
1796 return;
1797 }
1798 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001799
1800 // TODO: when underlying api has a direct way to do this we should use it
1801 // (e.g. glDrawPixels on desktop GL).
1802
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001803 // If the RT is also a texture and we don't have to do PM/UPM conversion
1804 // then take the texture path, which we expect to be at least as fast or
1805 // faster since it doesn't use an intermediate texture as we do below.
1806
1807#if !GR_MAC_BUILD
1808 // At least some drivers on the Mac get confused when glTexImage2D is called
1809 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1810 // determine what OS versions and/or HW is affected.
1811 if (NULL != target->asTexture() &&
1812 GrPixelConfigIsUnpremultiplied(target->config()) ==
1813 GrPixelConfigIsUnpremultiplied(config)) {
1814
1815 this->internalWriteTexturePixels(target->asTexture(),
1816 left, top, width, height,
1817 config, buffer, rowBytes, flags);
1818 return;
1819 }
1820#endif
1821
1822 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1823 GrPixelConfigSwapRAndB(config);
1824 if (swapRAndB) {
1825 config = GrPixelConfigSwapRAndB(config);
1826 }
1827
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001828 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001829 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001830 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001831 GrAutoScratchTexture ast(this, desc);
1832 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001833 if (NULL == texture) {
1834 return;
1835 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001836 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1837 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001838
bsalomon@google.com27847de2011-02-22 20:59:41 +00001839 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001840 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001841 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001842
1843 GrMatrix matrix;
1844 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001845 drawState->setViewMatrix(matrix);
1846 drawState->setRenderTarget(target);
1847 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001848
bsalomon@google.com5c638652011-07-18 19:31:59 +00001849 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001850 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1851 GrSamplerState::kNearest_Filter,
1852 matrix);
1853 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001854
1855 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1856 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001857 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001858 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1859 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001860 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001861 return;
1862 }
1863 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1864 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1865}
1866////////////////////////////////////////////////////////////////////////////////
1867
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001868void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001869 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001870
1871 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1872 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001873 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001874 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001875 if (paint.getTexture(i)) {
1876 *drawState->sampler(s) = paint.getTextureSampler(i);
1877 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001878 }
1879
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001880 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001881
1882 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1883 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001884 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001885 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001886 if (paint.getMask(i)) {
1887 *drawState->sampler(s) = paint.getMaskSampler(i);
1888 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001889 }
1890
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001891 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001892
1893 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001894 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001895 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001896 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001897 }
1898 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001899 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001900 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001901 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001902 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001903 if (paint.fColorMatrixEnabled) {
1904 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
1905 } else {
1906 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
1907 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001908 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001909 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001910 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001911
1912 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1913 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1914 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001915}
1916
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001917GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001918 DrawCategory category) {
1919 if (category != fLastDrawCategory) {
1920 flushDrawBuffer();
1921 fLastDrawCategory = category;
1922 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001923 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001924 GrDrawTarget* target = fGpu;
1925 switch (category) {
1926 case kText_DrawCategory:
1927#if DEFER_TEXT_RENDERING
1928 target = fDrawBuffer;
1929 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1930#else
1931 target = fGpu;
1932#endif
1933 break;
1934 case kUnbuffered_DrawCategory:
1935 target = fGpu;
1936 break;
1937 case kBuffered_DrawCategory:
1938 target = fDrawBuffer;
1939 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1940 break;
1941 }
1942 return target;
1943}
1944
bsalomon@google.com289533a2011-10-27 12:34:25 +00001945GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1946 GrPathFill fill,
1947 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001948 if (NULL == fPathRendererChain) {
1949 fPathRendererChain =
1950 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1951 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001952 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1953 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001954}
1955
bsalomon@google.com27847de2011-02-22 20:59:41 +00001956////////////////////////////////////////////////////////////////////////////////
1957
bsalomon@google.com27847de2011-02-22 20:59:41 +00001958void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001959 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001960 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001961 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001962}
1963
1964GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001965 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001966}
1967
1968const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001969 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001970}
1971
1972const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001973 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001974}
1975
1976void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001977 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001978}
1979
1980void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001981 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001982}
1983
1984static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1985 intptr_t mask = 1 << shift;
1986 if (pred) {
1987 bits |= mask;
1988 } else {
1989 bits &= ~mask;
1990 }
1991 return bits;
1992}
1993
1994void GrContext::resetStats() {
1995 fGpu->resetStats();
1996}
1997
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001998const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001999 return fGpu->getStats();
2000}
2001
2002void GrContext::printStats() const {
2003 fGpu->printStats();
2004}
2005
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002006GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002007 fGpu = gpu;
2008 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002009 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002010
bsalomon@google.com30085192011-08-19 15:42:31 +00002011 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002012
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002013 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2014 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002015 fFontCache = new GrFontCache(fGpu);
2016
2017 fLastDrawCategory = kUnbuffered_DrawCategory;
2018
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002019 fDrawBuffer = NULL;
2020 fDrawBufferVBAllocPool = NULL;
2021 fDrawBufferIBAllocPool = NULL;
2022
bsalomon@google.com205d4602011-04-25 12:43:45 +00002023 fAAFillRectIndexBuffer = NULL;
2024 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002025
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002026 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2027 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002028 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2029 }
2030 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002031
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002032 this->setupDrawBuffer();
2033}
2034
2035void GrContext::setupDrawBuffer() {
2036
2037 GrAssert(NULL == fDrawBuffer);
2038 GrAssert(NULL == fDrawBufferVBAllocPool);
2039 GrAssert(NULL == fDrawBufferIBAllocPool);
2040
bsalomon@google.com27847de2011-02-22 20:59:41 +00002041#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002042 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002043 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002044 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2045 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002046 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002047 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002048 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002049 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2050
bsalomon@google.com471d4712011-08-23 15:45:25 +00002051 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2052 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002053 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002054#endif
2055
2056#if BATCH_RECT_TO_RECT
2057 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2058#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002059}
2060
bsalomon@google.com27847de2011-02-22 20:59:41 +00002061GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2062 GrDrawTarget* target;
2063#if DEFER_TEXT_RENDERING
2064 target = prepareToDraw(paint, kText_DrawCategory);
2065#else
2066 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2067#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002068 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002069 return target;
2070}
2071
2072const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2073 return fGpu->getQuadIndexBuffer();
2074}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002075
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002076void GrContext::convolveInX(GrTexture* texture,
2077 const SkRect& rect,
2078 const float* kernel,
2079 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002080 ASSERT_OWNED_RESOURCE(texture);
2081
bsalomon@google.com99621082011-11-15 16:47:16 +00002082 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002083 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2084}
2085
2086void GrContext::convolveInY(GrTexture* texture,
2087 const SkRect& rect,
2088 const float* kernel,
2089 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002090 ASSERT_OWNED_RESOURCE(texture);
2091
bsalomon@google.com99621082011-11-15 16:47:16 +00002092 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002093 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2094}
2095
2096void GrContext::convolve(GrTexture* texture,
2097 const SkRect& rect,
2098 float imageIncrement[2],
2099 const float* kernel,
2100 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002101 ASSERT_OWNED_RESOURCE(texture);
2102
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002103 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002104 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002105 GrMatrix sampleM;
2106 sampleM.setIDiv(texture->width(), texture->height());
2107 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2108 GrSamplerState::kConvolution_Filter,
2109 sampleM);
2110 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2111 kernel,
2112 imageIncrement);
2113
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002114 drawState->setViewMatrix(GrMatrix::I());
2115 drawState->setTexture(0, texture);
2116 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002117 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002118 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2119}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002120
2121///////////////////////////////////////////////////////////////////////////////