blob: a301254213f5fc1a8e5c9e28648ac547250e55ed [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.com1fadb202011-12-12 16:10:08 +000010#include "GrContext.h"
11
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000014#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015#include "GrIndexBuffer.h"
16#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000017#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000018#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000020#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000021#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000022#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000023#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024
bsalomon@google.com91958362011-06-13 17:58:13 +000025// Using MSAA seems to be slower for some yet unknown reason.
26#define PREFER_MSAA_OFFSCREEN_AA 0
27#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000028
bsalomon@google.com27847de2011-02-22 20:59:41 +000029#define DEFER_TEXT_RENDERING 1
30
31#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
32
bsalomon@google.comd46e2422011-09-23 17:40:07 +000033// When we're using coverage AA but the blend is incompatible (given gpu
34// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000035#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000036
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000037static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000039
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
bsalomon@google.combc4b6542011-11-19 13:56:11 +000048#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
49
bsalomon@google.com05ef5102011-05-02 21:14:59 +000050GrContext* GrContext::Create(GrEngine engine,
51 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000052 GrContext* ctx = NULL;
53 GrGpu* fGpu = GrGpu::Create(engine, context3D);
54 if (NULL != fGpu) {
55 ctx = new GrContext(fGpu);
56 fGpu->unref();
57 }
58 return ctx;
59}
60
bsalomon@google.com27847de2011-02-22 20:59:41 +000061GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000068
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000072 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000073}
74
bsalomon@google.com8fe72472011-03-30 21:26:44 +000075void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000076 contextDestroyed();
77 this->setupDrawBuffer();
78}
79
80void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 // abandon first to so destructors
82 // don't try to free the resources in the API.
83 fGpu->abandonResources();
84
bsalomon@google.com30085192011-08-19 15:42:31 +000085 // a path renderer may be holding onto resources that
86 // are now unusable
87 GrSafeSetNull(fPathRendererChain);
88
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBuffer;
90 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferVBAllocPool;
93 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000094
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 delete fDrawBufferIBAllocPool;
96 fDrawBufferIBAllocPool = NULL;
97
bsalomon@google.com205d4602011-04-25 12:43:45 +000098 GrSafeSetNull(fAAFillRectIndexBuffer);
99 GrSafeSetNull(fAAStrokeRectIndexBuffer);
100
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101 fTextureCache->removeAll();
102 fFontCache->freeAll();
103 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000104}
105
106void GrContext::resetContext() {
107 fGpu->markContextDirty();
108}
109
110void GrContext::freeGpuResources() {
111 this->flush();
112 fTextureCache->removeAll();
113 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000114 // a path renderer may be holding onto resources
115 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000116}
117
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000118////////////////////////////////////////////////////////////////////////////////
119
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000120int GrContext::PaintStageVertexLayoutBits(
121 const GrPaint& paint,
122 const bool hasTexCoords[GrPaint::kTotalStages]) {
123 int stageMask = paint.getActiveStageMask();
124 int layout = 0;
125 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
126 if ((1 << i) & stageMask) {
127 if (NULL != hasTexCoords && hasTexCoords[i]) {
128 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
129 } else {
130 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
131 }
132 }
133 }
134 return layout;
135}
136
137
138////////////////////////////////////////////////////////////////////////////////
139
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000140enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000141 // flags for textures
142 kNPOTBit = 0x1,
143 kFilterBit = 0x2,
144 kScratchBit = 0x4,
145
146 // resource type
147 kTextureBit = 0x8,
148 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000149};
150
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000151GrTexture* GrContext::TextureCacheEntry::texture() const {
152 if (NULL == fEntry) {
153 return NULL;
154 } else {
155 return (GrTexture*) fEntry->resource();
156 }
157}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000158
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000159namespace {
160// returns true if this is a "special" texture because of gpu NPOT limitations
161bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000162 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163 GrContext::TextureKey clientKey,
164 int width,
165 int height,
166 bool scratch,
167 uint32_t v[4]) {
168 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
169 // we assume we only need 16 bits of width and height
170 // assert that texture creation will fail anyway if this assumption
171 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000172 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000173 v[0] = clientKey & 0xffffffffUL;
174 v[1] = (clientKey >> 32) & 0xffffffffUL;
175 v[2] = width | (height << 16);
176
177 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000178 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
180
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000181 bool tiled = NULL != sampler &&
182 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
183 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184
185 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000187 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 }
190 }
191 }
192
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 if (scratch) {
194 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197 v[3] |= kTextureBit;
198
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199 return v[3] & kNPOTBit;
200}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000201
202// we should never have more than one stencil buffer with same combo of
203// (width,height,samplecount)
204void gen_stencil_key_values(int width, int height,
205 int sampleCnt, uint32_t v[4]) {
206 v[0] = width;
207 v[1] = height;
208 v[2] = sampleCnt;
209 v[3] = kStencilBufferBit;
210}
211
212void gen_stencil_key_values(const GrStencilBuffer* sb,
213 uint32_t v[4]) {
214 gen_stencil_key_values(sb->width(), sb->height(),
215 sb->numSamples(), v);
216}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000217
218// This should be subsumed by a future version of GrDrawState
219// It does not reset stage textures/samplers or per-vertex-edge-aa state since
220// they aren't used unless the vertex layout references them.
221// It also doesn't set the render target.
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000222void reset_draw_state(GrDrawState* drawState){
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000223
224 drawState->setViewMatrix(GrMatrix::I());
225 drawState->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000226 drawState->resetStateFlags();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000227 drawState->setEdgeAAData(NULL, 0);
228 drawState->disableStencil();
229 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000230 drawState->setBlendFunc(kOne_BlendCoeff,
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000231 kZero_BlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000232 drawState->setFirstCoverageStage(GrDrawState::kNumStages);
233 drawState->setDrawFace(GrDrawState::kBoth_DrawFace);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000234}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000235}
236
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000237GrContext::TextureCacheEntry GrContext::findAndLockTexture(
238 TextureKey key,
239 int width,
240 int height,
241 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000242 uint32_t v[4];
243 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
244 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000245 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
246 GrResourceCache::kNested_LockType));
247}
248
bsalomon@google.comfb309512011-11-30 14:13:48 +0000249bool GrContext::isTextureInCache(TextureKey key,
250 int width,
251 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000252 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000253 uint32_t v[4];
254 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
255 GrResourceKey resourceKey(v);
256 return fTextureCache->hasKey(resourceKey);
257}
258
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000259GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000260 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000261 uint32_t v[4];
262 gen_stencil_key_values(sb, v);
263 GrResourceKey resourceKey(v);
264 return fTextureCache->createAndLock(resourceKey, sb);
265}
266
267GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
268 int sampleCnt) {
269 uint32_t v[4];
270 gen_stencil_key_values(width, height, sampleCnt, v);
271 GrResourceKey resourceKey(v);
272 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
273 GrResourceCache::kSingle_LockType);
274 if (NULL != entry) {
275 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
276 return sb;
277 } else {
278 return NULL;
279 }
280}
281
282void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000283 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000284 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000285}
286
287static void stretchImage(void* dst,
288 int dstW,
289 int dstH,
290 void* src,
291 int srcW,
292 int srcH,
293 int bpp) {
294 GrFixed dx = (srcW << 16) / dstW;
295 GrFixed dy = (srcH << 16) / dstH;
296
297 GrFixed y = dy >> 1;
298
299 int dstXLimit = dstW*bpp;
300 for (int j = 0; j < dstH; ++j) {
301 GrFixed x = dx >> 1;
302 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
303 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
304 for (int i = 0; i < dstXLimit; i += bpp) {
305 memcpy((uint8_t*) dstRow + i,
306 (uint8_t*) srcRow + (x>>16)*bpp,
307 bpp);
308 x += dx;
309 }
310 y += dy;
311 }
312}
313
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000314GrContext::TextureCacheEntry GrContext::createAndLockTexture(
315 TextureKey key,
316 const GrSamplerState* sampler,
317 const GrTextureDesc& desc,
318 void* srcData,
319 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000320 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000321
322#if GR_DUMP_TEXTURE_UPLOAD
323 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
324#endif
325
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000326 TextureCacheEntry entry;
327 uint32_t v[4];
328 bool special = gen_texture_key_values(fGpu, sampler, key,
329 desc.fWidth, desc.fHeight, false, v);
330 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000331
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000332 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000333 GrAssert(NULL != sampler);
334 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
335 desc.fWidth,
336 desc.fHeight,
337 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000338
339 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000340 clampEntry = this->createAndLockTexture(key, NULL, desc,
341 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000342 GrAssert(NULL != clampEntry.texture());
343 if (NULL == clampEntry.texture()) {
344 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000345 }
346 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000347 GrTextureDesc rtDesc = desc;
348 rtDesc.fFlags = rtDesc.fFlags |
349 kRenderTarget_GrTextureFlagBit |
350 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000351 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
352 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000353
354 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
355
356 if (NULL != texture) {
357 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000358 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000359 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000360 drawState->setRenderTarget(texture->asRenderTarget());
361 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000362
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000363 GrSamplerState::Filter filter;
364 // if filtering is not desired then we want to ensure all
365 // texels in the resampled image are copies of texels from
366 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000367 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000368 filter = GrSamplerState::kNearest_Filter;
369 } else {
370 filter = GrSamplerState::kBilinear_Filter;
371 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000372 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
373 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000374
375 static const GrVertexLayout layout =
376 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
377 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
378
379 if (arg.succeeded()) {
380 GrPoint* verts = (GrPoint*) arg.vertices();
381 verts[0].setIRectFan(0, 0,
382 texture->width(),
383 texture->height(),
384 2*sizeof(GrPoint));
385 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
386 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
387 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000388 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000390 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 } else {
392 // TODO: Our CPU stretch doesn't filter. But we create separate
393 // stretched textures when the sampler state is either filtered or
394 // not. Either implement filtered stretch blit on CPU or just create
395 // one when FBO case fails.
396
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000397 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 // no longer need to clamp at min RT size.
399 rtDesc.fWidth = GrNextPow2(desc.fWidth);
400 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000401 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000402 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000403 rtDesc.fWidth *
404 rtDesc.fHeight);
405 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
406 srcData, desc.fWidth, desc.fHeight, bpp);
407
408 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
409
410 GrTexture* texture = fGpu->createTexture(rtDesc,
411 stretchedPixels.get(),
412 stretchedRowBytes);
413 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000417
418 } else {
419 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
420 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000422 }
423 }
424 return entry;
425}
426
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427namespace {
428inline void gen_scratch_tex_key_values(const GrGpu* gpu,
429 const GrTextureDesc& desc,
430 uint32_t v[4]) {
431 // Instead of a client-provided key of the texture contents
432 // we create a key of from the descriptor.
433 GrContext::TextureKey descKey = desc.fAALevel |
434 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000435 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000436 // this code path isn't friendly to tiling with NPOT restricitons
437 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000438 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
439 desc.fHeight, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000440}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000441}
442
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000443GrContext::TextureCacheEntry GrContext::lockScratchTexture(
444 const GrTextureDesc& inDesc,
445 ScratchTexMatch match) {
446
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000447 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000448 if (kExact_ScratchTexMatch != match) {
449 // bin by pow2 with a reasonable min
450 static const int MIN_SIZE = 256;
451 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
452 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
453 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000454
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000455 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000456 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
457
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000458 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000459 int origWidth = desc.fWidth;
460 int origHeight = desc.fHeight;
461 bool doubledW = false;
462 bool doubledH = false;
463
464 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000465 uint32_t v[4];
466 gen_scratch_tex_key_values(fGpu, desc, v);
467 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000468 entry = fTextureCache->findAndLock(key,
469 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000470 // if we miss, relax the fit of the flags...
471 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000472 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000473 break;
474 }
475 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
476 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
477 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
478 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
479 } else if (!doubledW) {
480 desc.fFlags = inDesc.fFlags;
481 desc.fWidth *= 2;
482 doubledW = true;
483 } else if (!doubledH) {
484 desc.fFlags = inDesc.fFlags;
485 desc.fWidth = origWidth;
486 desc.fHeight *= 2;
487 doubledH = true;
488 } else {
489 break;
490 }
491
492 } while (true);
493
494 if (NULL == entry) {
495 desc.fFlags = inDesc.fFlags;
496 desc.fWidth = origWidth;
497 desc.fHeight = origHeight;
498 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
499 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000500 uint32_t v[4];
501 gen_scratch_tex_key_values(fGpu, desc, v);
502 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000503 entry = fTextureCache->createAndLock(key, texture);
504 }
505 }
506
507 // If the caller gives us the same desc/sampler twice we don't want
508 // to return the same texture the second time (unless it was previously
509 // released). So we detach the entry from the cache and reattach at release.
510 if (NULL != entry) {
511 fTextureCache->detach(entry);
512 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000514}
515
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000516void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000517 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518 // If this is a scratch texture we detached it from the cache
519 // while it was locked (to avoid two callers simultaneously getting
520 // the same texture).
521 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
522 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000523 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000524 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000525 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000526}
527
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000528GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000529 void* srcData,
530 size_t rowBytes) {
531 return fGpu->createTexture(desc, srcData, rowBytes);
532}
533
534void GrContext::getTextureCacheLimits(int* maxTextures,
535 size_t* maxTextureBytes) const {
536 fTextureCache->getLimits(maxTextures, maxTextureBytes);
537}
538
539void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
540 fTextureCache->setLimits(maxTextures, maxTextureBytes);
541}
542
bsalomon@google.com91958362011-06-13 17:58:13 +0000543int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000544 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000545}
546
547int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000548 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000549}
550
551///////////////////////////////////////////////////////////////////////////////
552
bsalomon@google.come269f212011-11-07 13:29:52 +0000553GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
554 return fGpu->createPlatformTexture(desc);
555}
556
557GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
558 return fGpu->createPlatformRenderTarget(desc);
559}
560
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000561GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
562 // validate flags here so that GrGpu subclasses don't have to check
563 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
564 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000565 return NULL;
566 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000567 if (desc.fSampleCnt &&
568 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000569 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000570 }
571 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
572 desc.fSampleCnt &&
573 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
574 return NULL;
575 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000576 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577}
578
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000579///////////////////////////////////////////////////////////////////////////////
580
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000581bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000582 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000583 const GrDrawTarget::Caps& caps = fGpu->getCaps();
584 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000585 return false;
586 }
587
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
589
590 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000591 bool tiled = NULL != sampler &&
592 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
593 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000594 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000595 return false;
596 }
597 }
598 return true;
599}
600
601////////////////////////////////////////////////////////////////////////////////
602
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000603const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
604
bsalomon@google.com27847de2011-02-22 20:59:41 +0000605void GrContext::setClip(const GrClip& clip) {
606 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000607 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000608}
609
610void GrContext::setClip(const GrIRect& rect) {
611 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000612 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000613 fGpu->setClip(clip);
614}
615
616////////////////////////////////////////////////////////////////////////////////
617
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000618void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000619 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000620 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000621}
622
623void GrContext::drawPaint(const GrPaint& paint) {
624 // set rect to be big enough to fill the space, but not super-huge, so we
625 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000626 GrRect r;
627 r.setLTRB(0, 0,
628 GrIntToScalar(getRenderTarget()->width()),
629 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000630 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000631 SkTLazy<GrPaint> tmpPaint;
632 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000633 GrDrawState* drawState = fGpu->drawState();
634 GrAutoMatrix am;
635
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000636 // We attempt to map r by the inverse matrix and draw that. mapRect will
637 // map the four corners and bound them with a new rect. This will not
638 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000639 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000640 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000641 GrPrintf("Could not invert matrix");
642 return;
643 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000644 inverse.mapRect(&r);
645 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000646 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000647 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000648 GrPrintf("Could not invert matrix");
649 return;
650 }
651 tmpPaint.set(paint);
652 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
653 p = tmpPaint.get();
654 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000655 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000657 // by definition this fills the entire clip, no need for AA
658 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000659 if (!tmpPaint.isValid()) {
660 tmpPaint.set(paint);
661 p = tmpPaint.get();
662 }
663 GrAssert(p == tmpPaint.get());
664 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000665 }
666 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000667}
668
bsalomon@google.com205d4602011-04-25 12:43:45 +0000669////////////////////////////////////////////////////////////////////////////////
670
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000671namespace {
672inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
673 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
674}
675}
676
bsalomon@google.com91958362011-06-13 17:58:13 +0000677struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000678 enum Downsample {
bsalomon@google.com91958362011-06-13 17:58:13 +0000679 k4x4SinglePass_Downsample,
680 kFSAA_Downsample
681 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000682 int fTileSizeX;
683 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000684 int fTileCountX;
685 int fTileCountY;
686 int fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000687 GrAutoScratchTexture fOffscreen;
bsalomon@google.com91958362011-06-13 17:58:13 +0000688 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000689 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000690};
691
bsalomon@google.com471d4712011-08-23 15:45:25 +0000692bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000693 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000694#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000695 return false;
696#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000697 // Line primitves are always rasterized as 1 pixel wide.
698 // Super-sampling would make them too thin but MSAA would be OK.
699 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000700 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000701 return false;
702 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000703 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000704 return false;
705 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000706 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000707#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000708 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000709#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000710 return false;
711 }
712 return true;
713#endif
714}
715
bsalomon@google.com91958362011-06-13 17:58:13 +0000716bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000717 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000718 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000719 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000720 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000721
722 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000723
bsalomon@google.com46579e02012-01-11 18:51:15 +0000724 GrAssert(NULL == record->fOffscreen.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000725 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000726
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000727 int boundW = boundRect.width();
728 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000729
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000730 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000731
732 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
733 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
734
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000735 if (requireStencil) {
736 desc.fFlags = kRenderTarget_GrTextureFlagBit;
737 } else {
738 desc.fFlags = kRenderTarget_GrTextureFlagBit |
739 kNoStencil_GrTextureFlagBit;
740 }
741
bsalomon@google.comc4364992011-11-07 15:54:49 +0000742 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000743
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000744 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000745 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000746 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000747 desc.fAALevel = kMed_GrAALevel;
748 } else {
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000749 record->fDownsample = OffscreenRecord::k4x4SinglePass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000750 record->fScale = OFFSCREEN_SSAA_SCALE;
751 // both downsample paths assume this
752 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000753 desc.fAALevel = kNone_GrAALevel;
754 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000755
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000756 desc.fWidth *= record->fScale;
757 desc.fHeight *= record->fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000758 record->fOffscreen.set(this, desc);
759 if (NULL == record->fOffscreen.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000760 return false;
761 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000762 // the approximate lookup might have given us some slop space, might as well
763 // use it when computing the tiles size.
764 // these are scale values, will adjust after considering
765 // the possible second offscreen.
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000766 record->fTileSizeX = record->fOffscreen.texture()->width();
767 record->fTileSizeY = record->fOffscreen.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000769 record->fTileSizeX /= record->fScale;
770 record->fTileSizeY /= record->fScale;
771
772 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
773 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
774
tomhudson@google.com237a4612011-07-19 15:44:00 +0000775 record->fClip = target->getClip();
776
bsalomon@google.com91958362011-06-13 17:58:13 +0000777 target->saveCurrentDrawState(&record->fSavedState);
778 return true;
779}
780
781void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
782 const GrIRect& boundRect,
783 int tileX, int tileY,
784 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000785
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000786 GrRenderTarget* offRT = record->fOffscreen.texture()->asRenderTarget();
787 GrAssert(NULL != offRT);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000788
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000789 GrPaint tempPaint;
790 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000791 this->setPaint(tempPaint, target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000792 GrDrawState* drawState = target->drawState();
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000793 drawState->setRenderTarget(offRT);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000794#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com337af172012-01-11 16:00:42 +0000795 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000796#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000797
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000798 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000799 int left = boundRect.fLeft + tileX * record->fTileSizeX;
800 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000801 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000802 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000803 GrMatrix scaleM;
804 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000805 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000806
bsalomon@google.com91958362011-06-13 17:58:13 +0000807 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000808 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000809 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000811 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
812 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000813 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000814#if 0
815 // visualize tile boundaries by setting edges of offscreen to white
816 // and interior to tranparent. black.
817 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000818
bsalomon@google.com91958362011-06-13 17:58:13 +0000819 static const int gOffset = 2;
820 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
821 record->fScale * w - gOffset,
822 record->fScale * h - gOffset);
823 target->clear(&clear2, 0x0);
824#else
825 target->clear(&clear, 0x0);
826#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000827}
828
bsalomon@google.com91958362011-06-13 17:58:13 +0000829void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000830 const GrPaint& paint,
831 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000832 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000833 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000834 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com46579e02012-01-11 18:51:15 +0000835 GrAssert(NULL != record->fOffscreen.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000836 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000837 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000838 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
839 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000840 tileRect.fRight = (tileX == record->fTileCountX-1) ?
841 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000842 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000843 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
844 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000845 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000846
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000847 GrSamplerState::Filter filter;
848 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
849 filter = GrSamplerState::k4x4Downsample_Filter;
850 } else {
851 filter = GrSamplerState::kBilinear_Filter;
852 }
853
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000854 GrTexture* src = record->fOffscreen.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000855 int scale;
856
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000857 enum {
858 kOffscreenStage = GrPaint::kTotalStages,
859 };
860
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000861 GrDrawState* drawState = target->drawState();
862
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000863 if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000865 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000866 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000867 } else {
868 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
869 record->fDownsample);
870 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871 }
872
bsalomon@google.com91958362011-06-13 17:58:13 +0000873 // setup for draw back to main RT, we use the original
874 // draw state setup by the caller plus an additional coverage
875 // stage to handle the AA resolve. Also, we use an identity
876 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000877 int stageMask = paint.getActiveStageMask();
878
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000879 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000880 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000881
882 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000883 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000884 if (drawState->getViewInverse(&invVM)) {
885 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000886 }
887 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000888 // This is important when tiling, otherwise second tile's
889 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000890 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000891
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000892 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000893 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
894 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000895 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
896 scale * GR_Scalar1 / src->height());
897 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
898 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000899
reed@google.com20efde72011-05-09 17:00:02 +0000900 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000901 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000902 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000903 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000904}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000905
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000906void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
907 GrPathRenderer* pr,
908 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000909 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000910}
911
912////////////////////////////////////////////////////////////////////////////////
913
bsalomon@google.com27847de2011-02-22 20:59:41 +0000914/* create a triangle strip that strokes the specified triangle. There are 8
915 unique vertices, but we repreat the last 2 to close up. Alternatively we
916 could use an indices array, and then only send 8 verts, but not sure that
917 would be faster.
918 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000919static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000920 GrScalar width) {
921 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000922 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000923
924 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
925 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
926 verts[2].set(rect.fRight - rad, rect.fTop + rad);
927 verts[3].set(rect.fRight + rad, rect.fTop - rad);
928 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
929 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
930 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
931 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
932 verts[8] = verts[0];
933 verts[9] = verts[1];
934}
935
bsalomon@google.com205d4602011-04-25 12:43:45 +0000936static void setInsetFan(GrPoint* pts, size_t stride,
937 const GrRect& r, GrScalar dx, GrScalar dy) {
938 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
939}
940
941static const uint16_t gFillAARectIdx[] = {
942 0, 1, 5, 5, 4, 0,
943 1, 2, 6, 6, 5, 1,
944 2, 3, 7, 7, 6, 2,
945 3, 0, 4, 4, 7, 3,
946 4, 5, 6, 6, 7, 4,
947};
948
949int GrContext::aaFillRectIndexCount() const {
950 return GR_ARRAY_COUNT(gFillAARectIdx);
951}
952
953GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
954 if (NULL == fAAFillRectIndexBuffer) {
955 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
956 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000957 if (NULL != fAAFillRectIndexBuffer) {
958 #if GR_DEBUG
959 bool updated =
960 #endif
961 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
962 sizeof(gFillAARectIdx));
963 GR_DEBUGASSERT(updated);
964 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000965 }
966 return fAAFillRectIndexBuffer;
967}
968
969static const uint16_t gStrokeAARectIdx[] = {
970 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
971 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
972 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
973 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
974
975 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
976 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
977 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
978 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
979
980 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
981 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
982 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
983 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
984};
985
986int GrContext::aaStrokeRectIndexCount() const {
987 return GR_ARRAY_COUNT(gStrokeAARectIdx);
988}
989
990GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
991 if (NULL == fAAStrokeRectIndexBuffer) {
992 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
993 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000994 if (NULL != fAAStrokeRectIndexBuffer) {
995 #if GR_DEBUG
996 bool updated =
997 #endif
998 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
999 sizeof(gStrokeAARectIdx));
1000 GR_DEBUGASSERT(updated);
1001 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001002 }
1003 return fAAStrokeRectIndexBuffer;
1004}
1005
bsalomon@google.coma3108262011-10-10 14:08:47 +00001006static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1007 bool useCoverage) {
1008 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001009 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001010 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001011 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1012 }
1013 }
1014 if (useCoverage) {
1015 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1016 } else {
1017 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1018 }
1019 return layout;
1020}
1021
bsalomon@google.com205d4602011-04-25 12:43:45 +00001022void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001023 const GrRect& devRect,
1024 bool useVertexCoverage) {
1025 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001026
1027 size_t vsize = GrDrawTarget::VertexSize(layout);
1028
1029 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001030 if (!geo.succeeded()) {
1031 GrPrintf("Failed to get space for vertices!\n");
1032 return;
1033 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001034 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1035 if (NULL == indexBuffer) {
1036 GrPrintf("Failed to create index buffer!\n");
1037 return;
1038 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001039
1040 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1041
1042 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1043 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1044
1045 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1046 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1047
1048 verts += sizeof(GrPoint);
1049 for (int i = 0; i < 4; ++i) {
1050 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1051 }
1052
bsalomon@google.coma3108262011-10-10 14:08:47 +00001053 GrColor innerColor;
1054 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001055 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001056 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001057 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 }
1059
bsalomon@google.com205d4602011-04-25 12:43:45 +00001060 verts += 4 * vsize;
1061 for (int i = 0; i < 4; ++i) {
1062 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1063 }
1064
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001065 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001066
1067 target->drawIndexed(kTriangles_PrimitiveType, 0,
1068 0, 8, this->aaFillRectIndexCount());
1069}
1070
bsalomon@google.coma3108262011-10-10 14:08:47 +00001071void GrContext::strokeAARect(GrDrawTarget* target,
1072 const GrRect& devRect,
1073 const GrVec& devStrokeSize,
1074 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001075 const GrScalar& dx = devStrokeSize.fX;
1076 const GrScalar& dy = devStrokeSize.fY;
1077 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1078 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1079
bsalomon@google.com205d4602011-04-25 12:43:45 +00001080 GrScalar spare;
1081 {
1082 GrScalar w = devRect.width() - dx;
1083 GrScalar h = devRect.height() - dy;
1084 spare = GrMin(w, h);
1085 }
1086
1087 if (spare <= 0) {
1088 GrRect r(devRect);
1089 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001090 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001091 return;
1092 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001093 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001094 size_t vsize = GrDrawTarget::VertexSize(layout);
1095
1096 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001097 if (!geo.succeeded()) {
1098 GrPrintf("Failed to get space for vertices!\n");
1099 return;
1100 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001101 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1102 if (NULL == indexBuffer) {
1103 GrPrintf("Failed to create index buffer!\n");
1104 return;
1105 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001106
1107 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1108
1109 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1110 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1111 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1112 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1113
1114 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1115 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1116 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1117 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1118
1119 verts += sizeof(GrPoint);
1120 for (int i = 0; i < 4; ++i) {
1121 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1122 }
1123
bsalomon@google.coma3108262011-10-10 14:08:47 +00001124 GrColor innerColor;
1125 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001126 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001127 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001128 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001129 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001130 verts += 4 * vsize;
1131 for (int i = 0; i < 8; ++i) {
1132 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1133 }
1134
1135 verts += 8 * vsize;
1136 for (int i = 0; i < 8; ++i) {
1137 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1138 }
1139
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001140 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001141 target->drawIndexed(kTriangles_PrimitiveType,
1142 0, 0, 16, aaStrokeRectIndexCount());
1143}
1144
reed@google.com20efde72011-05-09 17:00:02 +00001145/**
1146 * Returns true if the rects edges are integer-aligned.
1147 */
1148static bool isIRect(const GrRect& r) {
1149 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1150 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1151}
1152
bsalomon@google.com205d4602011-04-25 12:43:45 +00001153static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001154 const GrRect& rect,
1155 GrScalar width,
1156 const GrMatrix* matrix,
1157 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001158 GrRect* devRect,
1159 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001160 // we use a simple coverage ramp to do aa on axis-aligned rects
1161 // we check if the rect will be axis-aligned, and the rect won't land on
1162 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001163
bsalomon@google.coma3108262011-10-10 14:08:47 +00001164 // we are keeping around the "tweak the alpha" trick because
1165 // it is our only hope for the fixed-pipe implementation.
1166 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001167 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001168 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001169 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001170 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001171#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001172 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001173#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001174 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001175 } else {
1176 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001177 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001178 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001179 const GrDrawState& drawState = target->getDrawState();
1180 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001181 return false;
1182 }
1183
bsalomon@google.com471d4712011-08-23 15:45:25 +00001184 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001185 return false;
1186 }
1187
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001188 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001189 return false;
1190 }
1191
1192 if (NULL != matrix &&
1193 !matrix->preservesAxisAlignment()) {
1194 return false;
1195 }
1196
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001197 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001198 if (NULL != matrix) {
1199 combinedMatrix->preConcat(*matrix);
1200 GrAssert(combinedMatrix->preservesAxisAlignment());
1201 }
1202
1203 combinedMatrix->mapRect(devRect, rect);
1204 devRect->sort();
1205
1206 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001207 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001208 } else {
1209 return true;
1210 }
1211}
1212
bsalomon@google.com27847de2011-02-22 20:59:41 +00001213void GrContext::drawRect(const GrPaint& paint,
1214 const GrRect& rect,
1215 GrScalar width,
1216 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001217 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001218
1219 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001220 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001221
bsalomon@google.com205d4602011-04-25 12:43:45 +00001222 GrRect devRect = rect;
1223 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001224 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001225 bool needAA = paint.fAntiAlias &&
1226 !this->getRenderTarget()->isMultisampled();
1227 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1228 &combinedMatrix, &devRect,
1229 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001230
1231 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001232 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001233 if (width >= 0) {
1234 GrVec strokeSize;;
1235 if (width > 0) {
1236 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001237 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001238 strokeSize.setAbs(strokeSize);
1239 } else {
1240 strokeSize.set(GR_Scalar1, GR_Scalar1);
1241 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001242 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001243 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001244 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001245 }
1246 return;
1247 }
1248
bsalomon@google.com27847de2011-02-22 20:59:41 +00001249 if (width >= 0) {
1250 // TODO: consider making static vertex buffers for these cases.
1251 // Hairline could be done by just adding closing vertex to
1252 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001253 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1254
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255 static const int worstCaseVertCount = 10;
1256 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1257
1258 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001259 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001260 return;
1261 }
1262
1263 GrPrimitiveType primType;
1264 int vertCount;
1265 GrPoint* vertex = geo.positions();
1266
1267 if (width > 0) {
1268 vertCount = 10;
1269 primType = kTriangleStrip_PrimitiveType;
1270 setStrokeRectStrip(vertex, rect, width);
1271 } else {
1272 // hairline
1273 vertCount = 5;
1274 primType = kLineStrip_PrimitiveType;
1275 vertex[0].set(rect.fLeft, rect.fTop);
1276 vertex[1].set(rect.fRight, rect.fTop);
1277 vertex[2].set(rect.fRight, rect.fBottom);
1278 vertex[3].set(rect.fLeft, rect.fBottom);
1279 vertex[4].set(rect.fLeft, rect.fTop);
1280 }
1281
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001282 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001283 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001284 GrDrawState* drawState = target->drawState();
1285 avmr.set(drawState);
1286 drawState->preConcatViewMatrix(*matrix);
1287 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001288 }
1289
1290 target->drawNonIndexed(primType, 0, vertCount);
1291 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001292#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001293 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001294 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1295 if (NULL == sqVB) {
1296 GrPrintf("Failed to create static rect vb.\n");
1297 return;
1298 }
1299 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001300 GrDrawState* drawState = target->drawState();
1301 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001302 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001303 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001304 0, rect.height(), rect.fTop,
1305 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001306
1307 if (NULL != matrix) {
1308 m.postConcat(*matrix);
1309 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001310 drawState->preConcatViewMatrix(m);
1311 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001312
bsalomon@google.com27847de2011-02-22 20:59:41 +00001313 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001314#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001315 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001316#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317 }
1318}
1319
1320void GrContext::drawRectToRect(const GrPaint& paint,
1321 const GrRect& dstRect,
1322 const GrRect& srcRect,
1323 const GrMatrix* dstMatrix,
1324 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001325 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001327 // srcRect refers to paint's first texture
1328 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001329 drawRect(paint, dstRect, -1, dstMatrix);
1330 return;
1331 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001332
bsalomon@google.com27847de2011-02-22 20:59:41 +00001333 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1334
1335#if GR_STATIC_RECT_VB
1336 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001337 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001338 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001339 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001340
1341 GrMatrix m;
1342
1343 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1344 0, dstRect.height(), dstRect.fTop,
1345 0, 0, GrMatrix::I()[8]);
1346 if (NULL != dstMatrix) {
1347 m.postConcat(*dstMatrix);
1348 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001349 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001350
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001351 // srcRect refers to first stage
1352 int otherStageMask = paint.getActiveStageMask() &
1353 (~(1 << GrPaint::kFirstTextureStage));
1354 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001355 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001356 }
1357
bsalomon@google.com27847de2011-02-22 20:59:41 +00001358 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1359 0, srcRect.height(), srcRect.fTop,
1360 0, 0, GrMatrix::I()[8]);
1361 if (NULL != srcMatrix) {
1362 m.postConcat(*srcMatrix);
1363 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001364 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001365
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001366 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1367 if (NULL == sqVB) {
1368 GrPrintf("Failed to create static rect vb.\n");
1369 return;
1370 }
1371 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1373#else
1374
1375 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001376#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001378#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1380#endif
1381
tomhudson@google.com93813632011-10-27 20:21:16 +00001382 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1383 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001384 srcRects[0] = &srcRect;
1385 srcMatrices[0] = srcMatrix;
1386
1387 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1388#endif
1389}
1390
1391void GrContext::drawVertices(const GrPaint& paint,
1392 GrPrimitiveType primitiveType,
1393 int vertexCount,
1394 const GrPoint positions[],
1395 const GrPoint texCoords[],
1396 const GrColor colors[],
1397 const uint16_t indices[],
1398 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001399 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001400
1401 GrDrawTarget::AutoReleaseGeometry geo;
1402
1403 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1404
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001405 bool hasTexCoords[GrPaint::kTotalStages] = {
1406 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1407 0 // remaining stages use positions
1408 };
1409
1410 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411
1412 if (NULL != colors) {
1413 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001414 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001415 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416
1417 if (sizeof(GrPoint) != vertexSize) {
1418 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001419 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420 return;
1421 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001422 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001424 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1425 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001426 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001427 NULL,
1428 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001429 void* curVertex = geo.vertices();
1430
1431 for (int i = 0; i < vertexCount; ++i) {
1432 *((GrPoint*)curVertex) = positions[i];
1433
1434 if (texOffsets[0] > 0) {
1435 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1436 }
1437 if (colorOffset > 0) {
1438 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1439 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001440 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441 }
1442 } else {
1443 target->setVertexSourceToArray(layout, positions, vertexCount);
1444 }
1445
bsalomon@google.com91958362011-06-13 17:58:13 +00001446 // we don't currently apply offscreen AA to this path. Need improved
1447 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001448
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001449 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001450 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001451 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001452 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001453 target->drawNonIndexed(primitiveType, 0, vertexCount);
1454 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001455}
1456
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001457///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001458
reed@google.com07f3ee12011-05-16 17:21:57 +00001459void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1460 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001461
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001462 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001463 if (GrIsFillInverted(fill)) {
1464 this->drawPaint(paint);
1465 }
1466 return;
1467 }
1468
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001470
bsalomon@google.com289533a2011-10-27 12:34:25 +00001471 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1472
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001473 // An Assumption here is that path renderer would use some form of tweaking
1474 // the src color (either the input alpha or in the frag shader) to implement
1475 // aa. If we have some future driver-mojo path AA that can do the right
1476 // thing WRT to the blend then we'll need some query on the PR.
1477 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001478#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001479 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001480#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001481 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001482 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001483
1484 bool doOSAA = false;
1485 GrPathRenderer* pr = NULL;
1486 if (prAA) {
1487 pr = this->getPathRenderer(path, fill, true);
1488 if (NULL == pr) {
1489 prAA = false;
1490 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1491 pr = this->getPathRenderer(path, fill, false);
1492 }
1493 } else {
1494 pr = this->getPathRenderer(path, fill, false);
1495 }
1496
bsalomon@google.com30085192011-08-19 15:42:31 +00001497 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001498#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001499 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001500#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001501 return;
1502 }
1503
bsalomon@google.com289533a2011-10-27 12:34:25 +00001504 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001505 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001506
bsalomon@google.com289533a2011-10-27 12:34:25 +00001507 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001508 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001509 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001510 // compute bounds as intersection of rt size, clip, and path
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001511 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001512 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001513 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001514 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001515 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001516 return;
1517 }
1518 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001519 GrRect pathBounds = path.getBounds();
1520 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001521 if (NULL != translate) {
1522 pathBounds.offset(*translate);
1523 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001524 target->getDrawState().getViewMatrix().mapRect(&pathBounds,
1525 pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001526 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001527 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001528 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001529 return;
1530 }
1531 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001532 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001533 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1534 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001535 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1536 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1537 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001538 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001539 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1540 }
1541 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001542 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001543 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001544 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1545 GrRect rect;
1546 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001547 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1548 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001549 target->drawSimpleRect(rect, NULL, stageMask);
1550 }
1551 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001552 rect.iset(clipIBounds.fLeft, bound.fTop,
1553 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001554 target->drawSimpleRect(rect, NULL, stageMask);
1555 }
1556 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001557 rect.iset(bound.fRight, bound.fTop,
1558 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001559 target->drawSimpleRect(rect, NULL, stageMask);
1560 }
1561 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001562 rect.iset(clipIBounds.fLeft, bound.fBottom,
1563 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001564 target->drawSimpleRect(rect, NULL, stageMask);
1565 }
1566 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001567 return;
1568 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001569 }
1570 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001571}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001572
bsalomon@google.com27847de2011-02-22 20:59:41 +00001573////////////////////////////////////////////////////////////////////////////////
1574
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001575void GrContext::flush(int flagsBitfield) {
1576 if (kDiscard_FlushBit & flagsBitfield) {
1577 fDrawBuffer->reset();
1578 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001579 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001580 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001581 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001582 fGpu->forceRenderTargetFlush();
1583 }
1584}
1585
1586void GrContext::flushText() {
1587 if (kText_DrawCategory == fLastDrawCategory) {
1588 flushDrawBuffer();
1589 }
1590}
1591
1592void GrContext::flushDrawBuffer() {
1593#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001594 if (fDrawBuffer) {
1595 fDrawBuffer->playback(fGpu);
1596 fDrawBuffer->reset();
1597 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001598#endif
1599}
1600
bsalomon@google.com6f379512011-11-16 20:36:03 +00001601void GrContext::internalWriteTexturePixels(GrTexture* texture,
1602 int left, int top,
1603 int width, int height,
1604 GrPixelConfig config,
1605 const void* buffer,
1606 size_t rowBytes,
1607 uint32_t flags) {
1608 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001609 ASSERT_OWNED_RESOURCE(texture);
1610
bsalomon@google.com6f379512011-11-16 20:36:03 +00001611 if (!(kDontFlush_PixelOpsFlag & flags)) {
1612 this->flush();
1613 }
1614 // TODO: use scratch texture to perform conversion
1615 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1616 GrPixelConfigIsUnpremultiplied(config)) {
1617 return;
1618 }
1619
1620 fGpu->writeTexturePixels(texture, left, top, width, height,
1621 config, buffer, rowBytes);
1622}
1623
1624bool GrContext::internalReadTexturePixels(GrTexture* texture,
1625 int left, int top,
1626 int width, int height,
1627 GrPixelConfig config,
1628 void* buffer,
1629 size_t rowBytes,
1630 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001631 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001632 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001633
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001634 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001635 GrRenderTarget* target = texture->asRenderTarget();
1636 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001637 return this->internalReadRenderTargetPixels(target,
1638 left, top, width, height,
1639 config, buffer, rowBytes,
1640 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001641 } else {
1642 return false;
1643 }
1644}
1645
bsalomon@google.com6f379512011-11-16 20:36:03 +00001646bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1647 int left, int top,
1648 int width, int height,
1649 GrPixelConfig config,
1650 void* buffer,
1651 size_t rowBytes,
1652 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001653 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001654 ASSERT_OWNED_RESOURCE(target);
1655
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001656 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001657 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001658 if (NULL == target) {
1659 return false;
1660 }
1661 }
1662
1663 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1664 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1665 // not supported at this time.
1666 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1667 !GrPixelConfigIsUnpremultiplied(config)) {
1668 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001669 }
1670
bsalomon@google.com6f379512011-11-16 20:36:03 +00001671 if (!(kDontFlush_PixelOpsFlag & flags)) {
1672 this->flush();
1673 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001674
1675 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001676 bool swapRAndB = NULL != src &&
1677 fGpu->preferredReadPixelsConfig(config) ==
1678 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001679
1680 bool flipY = NULL != src &&
1681 fGpu->readPixelsWillPayForYFlip(target, left, top,
1682 width, height, config,
1683 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001684 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1685 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001686
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001687 if (NULL == src && alphaConversion) {
1688 // we should fallback to cpu conversion here. This could happen when
1689 // we were given an external render target by the client that is not
1690 // also a texture (e.g. FBO 0 in GL)
1691 return false;
1692 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001693 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001694 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001695 if (flipY || swapRAndB || alphaConversion) {
1696 GrAssert(NULL != src);
1697 if (swapRAndB) {
1698 config = GrPixelConfigSwapRAndB(config);
1699 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001700 }
1701 // Make the scratch a render target because we don't have a robust
1702 // readTexturePixels as of yet (it calls this function).
1703 const GrTextureDesc desc = {
1704 kRenderTarget_GrTextureFlagBit,
1705 kNone_GrAALevel,
1706 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001707 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001708 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001709
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001710 // When a full readback is faster than a partial we could always make
1711 // the scratch exactly match the passed rect. However, if we see many
1712 // different size rectangles we will trash our texture cache and pay the
1713 // cost of creating and destroying many textures. So, we only request
1714 // an exact match when the caller is reading an entire RT.
1715 ScratchTexMatch match = kApprox_ScratchTexMatch;
1716 if (0 == left &&
1717 0 == top &&
1718 target->width() == width &&
1719 target->height() == height &&
1720 fGpu->fullReadPixelsIsFasterThanPartial()) {
1721 match = kExact_ScratchTexMatch;
1722 }
1723 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001724 GrTexture* texture = ast.texture();
1725 if (!texture) {
1726 return false;
1727 }
1728 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001729 GrAssert(NULL != target);
1730
1731 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001732 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001733 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001734 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001735
bsalomon@google.comc4364992011-11-07 15:54:49 +00001736 GrMatrix matrix;
1737 if (flipY) {
1738 matrix.setTranslate(SK_Scalar1 * left,
1739 SK_Scalar1 * (top + height));
1740 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1741 } else {
1742 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1743 }
1744 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001745 drawState->sampler(0)->reset(matrix);
1746 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001747 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001748 GrRect rect;
1749 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1750 fGpu->drawSimpleRect(rect, NULL, 0x1);
1751 left = 0;
1752 top = 0;
1753 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001754 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001755 left, top, width, height,
1756 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001757}
1758
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001759void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1760 if (NULL == src || NULL == dst) {
1761 return;
1762 }
1763 ASSERT_OWNED_RESOURCE(src);
1764
1765 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001766 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001767 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001768 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001769 GrMatrix sampleM;
1770 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001771 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001772 drawState->sampler(0)->reset(sampleM);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001773 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1774 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1775}
1776
bsalomon@google.com6f379512011-11-16 20:36:03 +00001777void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1778 int left, int top,
1779 int width, int height,
1780 GrPixelConfig config,
1781 const void* buffer,
1782 size_t rowBytes,
1783 uint32_t flags) {
1784 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001785 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001786
1787 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001788 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001789 if (NULL == target) {
1790 return;
1791 }
1792 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001793
1794 // TODO: when underlying api has a direct way to do this we should use it
1795 // (e.g. glDrawPixels on desktop GL).
1796
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001797 // If the RT is also a texture and we don't have to do PM/UPM conversion
1798 // then take the texture path, which we expect to be at least as fast or
1799 // faster since it doesn't use an intermediate texture as we do below.
1800
1801#if !GR_MAC_BUILD
1802 // At least some drivers on the Mac get confused when glTexImage2D is called
1803 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1804 // determine what OS versions and/or HW is affected.
1805 if (NULL != target->asTexture() &&
1806 GrPixelConfigIsUnpremultiplied(target->config()) ==
1807 GrPixelConfigIsUnpremultiplied(config)) {
1808
1809 this->internalWriteTexturePixels(target->asTexture(),
1810 left, top, width, height,
1811 config, buffer, rowBytes, flags);
1812 return;
1813 }
1814#endif
1815
1816 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1817 GrPixelConfigSwapRAndB(config);
1818 if (swapRAndB) {
1819 config = GrPixelConfigSwapRAndB(config);
1820 }
1821
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001822 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001823 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001824 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001825 GrAutoScratchTexture ast(this, desc);
1826 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001827 if (NULL == texture) {
1828 return;
1829 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001830 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1831 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001832
bsalomon@google.com27847de2011-02-22 20:59:41 +00001833 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001834 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001835 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001836
1837 GrMatrix matrix;
1838 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001839 drawState->setViewMatrix(matrix);
1840 drawState->setRenderTarget(target);
1841 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001842
bsalomon@google.com5c638652011-07-18 19:31:59 +00001843 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001844 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1845 GrSamplerState::kNearest_Filter,
1846 matrix);
1847 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001848
1849 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1850 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001851 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001852 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1853 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001854 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001855 return;
1856 }
1857 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1858 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1859}
1860////////////////////////////////////////////////////////////////////////////////
1861
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001862void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001863 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001864
1865 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1866 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001867 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001868 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001869 if (paint.getTexture(i)) {
1870 *drawState->sampler(s) = paint.getTextureSampler(i);
1871 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001872 }
1873
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001874 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001875
1876 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1877 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001878 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001879 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001880 if (paint.getMask(i)) {
1881 *drawState->sampler(s) = paint.getMaskSampler(i);
1882 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001883 }
1884
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001885 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001886
1887 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001888 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001890 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001891 }
1892 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001893 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001894 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001895 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001896 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001897 if (paint.fColorMatrixEnabled) {
1898 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
1899 } else {
1900 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
1901 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001902 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001903 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001904 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001905
1906 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1907 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1908 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001909}
1910
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001911GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001912 DrawCategory category) {
1913 if (category != fLastDrawCategory) {
1914 flushDrawBuffer();
1915 fLastDrawCategory = category;
1916 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001917 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001918 GrDrawTarget* target = fGpu;
1919 switch (category) {
1920 case kText_DrawCategory:
1921#if DEFER_TEXT_RENDERING
1922 target = fDrawBuffer;
1923 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1924#else
1925 target = fGpu;
1926#endif
1927 break;
1928 case kUnbuffered_DrawCategory:
1929 target = fGpu;
1930 break;
1931 case kBuffered_DrawCategory:
1932 target = fDrawBuffer;
1933 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1934 break;
1935 }
1936 return target;
1937}
1938
bsalomon@google.com289533a2011-10-27 12:34:25 +00001939GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1940 GrPathFill fill,
1941 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001942 if (NULL == fPathRendererChain) {
1943 fPathRendererChain =
1944 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1945 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001946 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1947 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001948}
1949
bsalomon@google.com27847de2011-02-22 20:59:41 +00001950////////////////////////////////////////////////////////////////////////////////
1951
bsalomon@google.com27847de2011-02-22 20:59:41 +00001952void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001953 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001954 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001955 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001956}
1957
1958GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001959 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001960}
1961
1962const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001963 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001964}
1965
1966const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001967 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001968}
1969
1970void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001971 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001972}
1973
1974void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001975 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001976}
1977
1978static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1979 intptr_t mask = 1 << shift;
1980 if (pred) {
1981 bits |= mask;
1982 } else {
1983 bits &= ~mask;
1984 }
1985 return bits;
1986}
1987
1988void GrContext::resetStats() {
1989 fGpu->resetStats();
1990}
1991
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001992const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993 return fGpu->getStats();
1994}
1995
1996void GrContext::printStats() const {
1997 fGpu->printStats();
1998}
1999
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002000GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002001 fGpu = gpu;
2002 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002003 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002004
bsalomon@google.com30085192011-08-19 15:42:31 +00002005 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002006
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002007 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2008 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002009 fFontCache = new GrFontCache(fGpu);
2010
2011 fLastDrawCategory = kUnbuffered_DrawCategory;
2012
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002013 fDrawBuffer = NULL;
2014 fDrawBufferVBAllocPool = NULL;
2015 fDrawBufferIBAllocPool = NULL;
2016
bsalomon@google.com205d4602011-04-25 12:43:45 +00002017 fAAFillRectIndexBuffer = NULL;
2018 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002019
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002020 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2021 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002022 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2023 }
2024 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002025
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002026 this->setupDrawBuffer();
2027}
2028
2029void GrContext::setupDrawBuffer() {
2030
2031 GrAssert(NULL == fDrawBuffer);
2032 GrAssert(NULL == fDrawBufferVBAllocPool);
2033 GrAssert(NULL == fDrawBufferIBAllocPool);
2034
bsalomon@google.com27847de2011-02-22 20:59:41 +00002035#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002036 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002037 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002038 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2039 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002040 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002041 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002042 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002043 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2044
bsalomon@google.com471d4712011-08-23 15:45:25 +00002045 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2046 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002047 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002048#endif
2049
2050#if BATCH_RECT_TO_RECT
2051 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2052#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002053}
2054
bsalomon@google.com27847de2011-02-22 20:59:41 +00002055GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2056 GrDrawTarget* target;
2057#if DEFER_TEXT_RENDERING
2058 target = prepareToDraw(paint, kText_DrawCategory);
2059#else
2060 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2061#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002062 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002063 return target;
2064}
2065
2066const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2067 return fGpu->getQuadIndexBuffer();
2068}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002069
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002070void GrContext::convolveInX(GrTexture* texture,
2071 const SkRect& rect,
2072 const float* kernel,
2073 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002074 ASSERT_OWNED_RESOURCE(texture);
2075
bsalomon@google.com99621082011-11-15 16:47:16 +00002076 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002077 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2078}
2079
2080void GrContext::convolveInY(GrTexture* texture,
2081 const SkRect& rect,
2082 const float* kernel,
2083 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002084 ASSERT_OWNED_RESOURCE(texture);
2085
bsalomon@google.com99621082011-11-15 16:47:16 +00002086 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002087 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2088}
2089
2090void GrContext::convolve(GrTexture* texture,
2091 const SkRect& rect,
2092 float imageIncrement[2],
2093 const float* kernel,
2094 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002095 ASSERT_OWNED_RESOURCE(texture);
2096
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002097 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002098 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002099 GrMatrix sampleM;
2100 sampleM.setIDiv(texture->width(), texture->height());
2101 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2102 GrSamplerState::kConvolution_Filter,
2103 sampleM);
2104 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2105 kernel,
2106 imageIncrement);
2107
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002108 drawState->setViewMatrix(GrMatrix::I());
2109 drawState->setTexture(0, texture);
2110 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002111 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002112 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2113}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002114
2115///////////////////////////////////////////////////////////////////////////////