blob: 335c1ef3eb7ffb8154ac3617943351cc3d91ad53 [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 {
679 k4x4TwoPass_Downsample,
680 k4x4SinglePass_Downsample,
681 kFSAA_Downsample
682 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000683 int fTileSizeX;
684 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000685 int fTileCountX;
686 int fTileCountY;
687 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000688 GrAutoScratchTexture fOffscreen0;
689 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000690 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000691 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000692};
693
bsalomon@google.com471d4712011-08-23 15:45:25 +0000694bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000695 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000696#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000697 return false;
698#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000699 // Line primitves are always rasterized as 1 pixel wide.
700 // Super-sampling would make them too thin but MSAA would be OK.
701 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000702 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000703 return false;
704 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000705 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000706 return false;
707 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000708 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000709#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000710 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000711#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000712 return false;
713 }
714 return true;
715#endif
716}
717
bsalomon@google.com91958362011-06-13 17:58:13 +0000718bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000719 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000720 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000721 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000722 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000723
724 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000725
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000726 GrAssert(NULL == record->fOffscreen0.texture());
727 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000728 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000730 int boundW = boundRect.width();
731 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000732
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000733 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000734
735 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
736 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
737
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000738 if (requireStencil) {
739 desc.fFlags = kRenderTarget_GrTextureFlagBit;
740 } else {
741 desc.fFlags = kRenderTarget_GrTextureFlagBit |
742 kNoStencil_GrTextureFlagBit;
743 }
744
bsalomon@google.comc4364992011-11-07 15:54:49 +0000745 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000746
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000747 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000748 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000749 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000750 desc.fAALevel = kMed_GrAALevel;
751 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000752 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000753 OffscreenRecord::k4x4SinglePass_Downsample :
754 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000755 record->fScale = OFFSCREEN_SSAA_SCALE;
756 // both downsample paths assume this
757 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000758 desc.fAALevel = kNone_GrAALevel;
759 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000760
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000761 desc.fWidth *= record->fScale;
762 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000763 record->fOffscreen0.set(this, desc);
764 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000765 return false;
766 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000767 // the approximate lookup might have given us some slop space, might as well
768 // use it when computing the tiles size.
769 // these are scale values, will adjust after considering
770 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000771 record->fTileSizeX = record->fOffscreen0.texture()->width();
772 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000773
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000774 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000775 desc.fWidth /= 2;
776 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000777 record->fOffscreen1.set(this, desc);
778 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000779 return false;
780 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000781 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000782 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000783 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000784 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000785 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000786 record->fTileSizeX /= record->fScale;
787 record->fTileSizeY /= record->fScale;
788
789 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
790 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
791
tomhudson@google.com237a4612011-07-19 15:44:00 +0000792 record->fClip = target->getClip();
793
bsalomon@google.com91958362011-06-13 17:58:13 +0000794 target->saveCurrentDrawState(&record->fSavedState);
795 return true;
796}
797
798void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
799 const GrIRect& boundRect,
800 int tileX, int tileY,
801 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000802
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000803 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000804 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000805
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000806 GrPaint tempPaint;
807 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000808 this->setPaint(tempPaint, target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000809 GrDrawState* drawState = target->drawState();
810 drawState->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000811#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000812 target->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000813#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000814
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000815 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000816 int left = boundRect.fLeft + tileX * record->fTileSizeX;
817 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000818 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000819 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000820 GrMatrix scaleM;
821 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000822 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000823
bsalomon@google.com91958362011-06-13 17:58:13 +0000824 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000825 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000826 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000827 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000828 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
829 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000830 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000831#if 0
832 // visualize tile boundaries by setting edges of offscreen to white
833 // and interior to tranparent. black.
834 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000835
bsalomon@google.com91958362011-06-13 17:58:13 +0000836 static const int gOffset = 2;
837 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
838 record->fScale * w - gOffset,
839 record->fScale * h - gOffset);
840 target->clear(&clear2, 0x0);
841#else
842 target->clear(&clear, 0x0);
843#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000844}
845
bsalomon@google.com91958362011-06-13 17:58:13 +0000846void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000847 const GrPaint& paint,
848 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000849 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000850 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000851 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000852 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000853 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000854 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000855 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
856 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000857 tileRect.fRight = (tileX == record->fTileCountX-1) ?
858 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000859 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000860 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
861 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000862 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000863
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000864 GrSamplerState::Filter filter;
865 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
866 filter = GrSamplerState::k4x4Downsample_Filter;
867 } else {
868 filter = GrSamplerState::kBilinear_Filter;
869 }
870
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000871 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 int scale;
873
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000874 enum {
875 kOffscreenStage = GrPaint::kTotalStages,
876 };
877
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000878 GrDrawState* drawState = target->drawState();
879
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000880 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000881 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000882 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000883 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000884
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000885 // Do 2x2 downsample from first to second
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000886 drawState->setTexture(kOffscreenStage, src);
887 drawState->setRenderTarget(dst);
888 drawState->setViewMatrix(GrMatrix::I());
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000889 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
890 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000891 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
892 scale * GR_Scalar1 / src->height());
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000893 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
894 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000895 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
896
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000897 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000898 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000899 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000900 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000901 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000902 } else {
903 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
904 record->fDownsample);
905 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000906 }
907
bsalomon@google.com91958362011-06-13 17:58:13 +0000908 // setup for draw back to main RT, we use the original
909 // draw state setup by the caller plus an additional coverage
910 // stage to handle the AA resolve. Also, we use an identity
911 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000912 int stageMask = paint.getActiveStageMask();
913
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000914 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000915 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000916
917 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000918 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000919 if (drawState->getViewInverse(&invVM)) {
920 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000921 }
922 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000923 // This is important when tiling, otherwise second tile's
924 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000925 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000926
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000927 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000928 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
929 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000930 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
931 scale * GR_Scalar1 / src->height());
932 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
933 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000934
reed@google.com20efde72011-05-09 17:00:02 +0000935 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000936 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000937 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000938 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000939}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000940
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000941void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
942 GrPathRenderer* pr,
943 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000944 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000945}
946
947////////////////////////////////////////////////////////////////////////////////
948
bsalomon@google.com27847de2011-02-22 20:59:41 +0000949/* create a triangle strip that strokes the specified triangle. There are 8
950 unique vertices, but we repreat the last 2 to close up. Alternatively we
951 could use an indices array, and then only send 8 verts, but not sure that
952 would be faster.
953 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000954static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000955 GrScalar width) {
956 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000957 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000958
959 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
960 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
961 verts[2].set(rect.fRight - rad, rect.fTop + rad);
962 verts[3].set(rect.fRight + rad, rect.fTop - rad);
963 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
964 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
965 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
966 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
967 verts[8] = verts[0];
968 verts[9] = verts[1];
969}
970
bsalomon@google.com205d4602011-04-25 12:43:45 +0000971static void setInsetFan(GrPoint* pts, size_t stride,
972 const GrRect& r, GrScalar dx, GrScalar dy) {
973 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
974}
975
976static const uint16_t gFillAARectIdx[] = {
977 0, 1, 5, 5, 4, 0,
978 1, 2, 6, 6, 5, 1,
979 2, 3, 7, 7, 6, 2,
980 3, 0, 4, 4, 7, 3,
981 4, 5, 6, 6, 7, 4,
982};
983
984int GrContext::aaFillRectIndexCount() const {
985 return GR_ARRAY_COUNT(gFillAARectIdx);
986}
987
988GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
989 if (NULL == fAAFillRectIndexBuffer) {
990 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
991 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000992 if (NULL != fAAFillRectIndexBuffer) {
993 #if GR_DEBUG
994 bool updated =
995 #endif
996 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
997 sizeof(gFillAARectIdx));
998 GR_DEBUGASSERT(updated);
999 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001000 }
1001 return fAAFillRectIndexBuffer;
1002}
1003
1004static const uint16_t gStrokeAARectIdx[] = {
1005 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
1006 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1007 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1008 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1009
1010 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1011 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1012 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1013 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1014
1015 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1016 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1017 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1018 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1019};
1020
1021int GrContext::aaStrokeRectIndexCount() const {
1022 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1023}
1024
1025GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1026 if (NULL == fAAStrokeRectIndexBuffer) {
1027 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1028 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001029 if (NULL != fAAStrokeRectIndexBuffer) {
1030 #if GR_DEBUG
1031 bool updated =
1032 #endif
1033 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1034 sizeof(gStrokeAARectIdx));
1035 GR_DEBUGASSERT(updated);
1036 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001037 }
1038 return fAAStrokeRectIndexBuffer;
1039}
1040
bsalomon@google.coma3108262011-10-10 14:08:47 +00001041static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1042 bool useCoverage) {
1043 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001044 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001045 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001046 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1047 }
1048 }
1049 if (useCoverage) {
1050 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1051 } else {
1052 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1053 }
1054 return layout;
1055}
1056
bsalomon@google.com205d4602011-04-25 12:43:45 +00001057void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 const GrRect& devRect,
1059 bool useVertexCoverage) {
1060 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001061
1062 size_t vsize = GrDrawTarget::VertexSize(layout);
1063
1064 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001065 if (!geo.succeeded()) {
1066 GrPrintf("Failed to get space for vertices!\n");
1067 return;
1068 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001069 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1070 if (NULL == indexBuffer) {
1071 GrPrintf("Failed to create index buffer!\n");
1072 return;
1073 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001074
1075 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1076
1077 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1078 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1079
1080 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1081 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1082
1083 verts += sizeof(GrPoint);
1084 for (int i = 0; i < 4; ++i) {
1085 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1086 }
1087
bsalomon@google.coma3108262011-10-10 14:08:47 +00001088 GrColor innerColor;
1089 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001090 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001091 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001092 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001093 }
1094
bsalomon@google.com205d4602011-04-25 12:43:45 +00001095 verts += 4 * vsize;
1096 for (int i = 0; i < 4; ++i) {
1097 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1098 }
1099
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001100 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001101
1102 target->drawIndexed(kTriangles_PrimitiveType, 0,
1103 0, 8, this->aaFillRectIndexCount());
1104}
1105
bsalomon@google.coma3108262011-10-10 14:08:47 +00001106void GrContext::strokeAARect(GrDrawTarget* target,
1107 const GrRect& devRect,
1108 const GrVec& devStrokeSize,
1109 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001110 const GrScalar& dx = devStrokeSize.fX;
1111 const GrScalar& dy = devStrokeSize.fY;
1112 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1113 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1114
bsalomon@google.com205d4602011-04-25 12:43:45 +00001115 GrScalar spare;
1116 {
1117 GrScalar w = devRect.width() - dx;
1118 GrScalar h = devRect.height() - dy;
1119 spare = GrMin(w, h);
1120 }
1121
1122 if (spare <= 0) {
1123 GrRect r(devRect);
1124 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001125 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001126 return;
1127 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001128 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001129 size_t vsize = GrDrawTarget::VertexSize(layout);
1130
1131 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001132 if (!geo.succeeded()) {
1133 GrPrintf("Failed to get space for vertices!\n");
1134 return;
1135 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001136 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1137 if (NULL == indexBuffer) {
1138 GrPrintf("Failed to create index buffer!\n");
1139 return;
1140 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001141
1142 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1143
1144 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1145 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1146 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1147 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1148
1149 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1150 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1151 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1152 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1153
1154 verts += sizeof(GrPoint);
1155 for (int i = 0; i < 4; ++i) {
1156 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1157 }
1158
bsalomon@google.coma3108262011-10-10 14:08:47 +00001159 GrColor innerColor;
1160 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001161 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001162 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001163 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001164 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001165 verts += 4 * vsize;
1166 for (int i = 0; i < 8; ++i) {
1167 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1168 }
1169
1170 verts += 8 * vsize;
1171 for (int i = 0; i < 8; ++i) {
1172 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1173 }
1174
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001175 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001176 target->drawIndexed(kTriangles_PrimitiveType,
1177 0, 0, 16, aaStrokeRectIndexCount());
1178}
1179
reed@google.com20efde72011-05-09 17:00:02 +00001180/**
1181 * Returns true if the rects edges are integer-aligned.
1182 */
1183static bool isIRect(const GrRect& r) {
1184 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1185 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1186}
1187
bsalomon@google.com205d4602011-04-25 12:43:45 +00001188static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001189 const GrRect& rect,
1190 GrScalar width,
1191 const GrMatrix* matrix,
1192 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001193 GrRect* devRect,
1194 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001195 // we use a simple alpha ramp to do aa on axis-aligned rects
1196 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001197 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001198
bsalomon@google.coma3108262011-10-10 14:08:47 +00001199 // we are keeping around the "tweak the alpha" trick because
1200 // it is our only hope for the fixed-pipe implementation.
1201 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001202 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001203 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001204 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001205 if (target->getCaps().fSupportPerVertexCoverage) {
1206 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001207#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001208 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001209#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001210 return false;
1211 } else {
1212 *useVertexCoverage = true;
1213 }
1214 } else {
1215 GrPrintf("Rect AA dropped because no support for coverage.\n");
1216 return false;
1217 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001218 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001219 const GrDrawState& drawState = target->getDrawState();
1220 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001221 return false;
1222 }
1223
bsalomon@google.com471d4712011-08-23 15:45:25 +00001224 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001225 return false;
1226 }
1227
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001228 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001229 return false;
1230 }
1231
1232 if (NULL != matrix &&
1233 !matrix->preservesAxisAlignment()) {
1234 return false;
1235 }
1236
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001237 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001238 if (NULL != matrix) {
1239 combinedMatrix->preConcat(*matrix);
1240 GrAssert(combinedMatrix->preservesAxisAlignment());
1241 }
1242
1243 combinedMatrix->mapRect(devRect, rect);
1244 devRect->sort();
1245
1246 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001247 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001248 } else {
1249 return true;
1250 }
1251}
1252
bsalomon@google.com27847de2011-02-22 20:59:41 +00001253void GrContext::drawRect(const GrPaint& paint,
1254 const GrRect& rect,
1255 GrScalar width,
1256 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001257 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258
1259 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001260 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001261
bsalomon@google.com205d4602011-04-25 12:43:45 +00001262 GrRect devRect = rect;
1263 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001264 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001265 bool needAA = paint.fAntiAlias &&
1266 !this->getRenderTarget()->isMultisampled();
1267 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1268 &combinedMatrix, &devRect,
1269 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001270
1271 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001272 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001273 if (width >= 0) {
1274 GrVec strokeSize;;
1275 if (width > 0) {
1276 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001277 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001278 strokeSize.setAbs(strokeSize);
1279 } else {
1280 strokeSize.set(GR_Scalar1, GR_Scalar1);
1281 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001282 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001283 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001284 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001285 }
1286 return;
1287 }
1288
bsalomon@google.com27847de2011-02-22 20:59:41 +00001289 if (width >= 0) {
1290 // TODO: consider making static vertex buffers for these cases.
1291 // Hairline could be done by just adding closing vertex to
1292 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001293 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1294
bsalomon@google.com27847de2011-02-22 20:59:41 +00001295 static const int worstCaseVertCount = 10;
1296 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1297
1298 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001299 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300 return;
1301 }
1302
1303 GrPrimitiveType primType;
1304 int vertCount;
1305 GrPoint* vertex = geo.positions();
1306
1307 if (width > 0) {
1308 vertCount = 10;
1309 primType = kTriangleStrip_PrimitiveType;
1310 setStrokeRectStrip(vertex, rect, width);
1311 } else {
1312 // hairline
1313 vertCount = 5;
1314 primType = kLineStrip_PrimitiveType;
1315 vertex[0].set(rect.fLeft, rect.fTop);
1316 vertex[1].set(rect.fRight, rect.fTop);
1317 vertex[2].set(rect.fRight, rect.fBottom);
1318 vertex[3].set(rect.fLeft, rect.fBottom);
1319 vertex[4].set(rect.fLeft, rect.fTop);
1320 }
1321
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001322 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001323 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001324 GrDrawState* drawState = target->drawState();
1325 avmr.set(drawState);
1326 drawState->preConcatViewMatrix(*matrix);
1327 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001328 }
1329
1330 target->drawNonIndexed(primType, 0, vertCount);
1331 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001332#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001333 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001334 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1335 if (NULL == sqVB) {
1336 GrPrintf("Failed to create static rect vb.\n");
1337 return;
1338 }
1339 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001340 GrDrawState* drawState = target->drawState();
1341 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001342 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001343 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001344 0, rect.height(), rect.fTop,
1345 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001346
1347 if (NULL != matrix) {
1348 m.postConcat(*matrix);
1349 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001350 drawState->preConcatViewMatrix(m);
1351 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001352
bsalomon@google.com27847de2011-02-22 20:59:41 +00001353 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001354#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001355 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001356#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001357 }
1358}
1359
1360void GrContext::drawRectToRect(const GrPaint& paint,
1361 const GrRect& dstRect,
1362 const GrRect& srcRect,
1363 const GrMatrix* dstMatrix,
1364 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001365 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001366
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001367 // srcRect refers to paint's first texture
1368 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001369 drawRect(paint, dstRect, -1, dstMatrix);
1370 return;
1371 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001372
bsalomon@google.com27847de2011-02-22 20:59:41 +00001373 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1374
1375#if GR_STATIC_RECT_VB
1376 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001377 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001378 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001379 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001380
1381 GrMatrix m;
1382
1383 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1384 0, dstRect.height(), dstRect.fTop,
1385 0, 0, GrMatrix::I()[8]);
1386 if (NULL != dstMatrix) {
1387 m.postConcat(*dstMatrix);
1388 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001389 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001390
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001391 // srcRect refers to first stage
1392 int otherStageMask = paint.getActiveStageMask() &
1393 (~(1 << GrPaint::kFirstTextureStage));
1394 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001395 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001396 }
1397
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1399 0, srcRect.height(), srcRect.fTop,
1400 0, 0, GrMatrix::I()[8]);
1401 if (NULL != srcMatrix) {
1402 m.postConcat(*srcMatrix);
1403 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001404 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001406 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1407 if (NULL == sqVB) {
1408 GrPrintf("Failed to create static rect vb.\n");
1409 return;
1410 }
1411 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001412 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1413#else
1414
1415 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001416#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001418#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001419 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1420#endif
1421
tomhudson@google.com93813632011-10-27 20:21:16 +00001422 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1423 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001424 srcRects[0] = &srcRect;
1425 srcMatrices[0] = srcMatrix;
1426
1427 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1428#endif
1429}
1430
1431void GrContext::drawVertices(const GrPaint& paint,
1432 GrPrimitiveType primitiveType,
1433 int vertexCount,
1434 const GrPoint positions[],
1435 const GrPoint texCoords[],
1436 const GrColor colors[],
1437 const uint16_t indices[],
1438 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001439 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001440
1441 GrDrawTarget::AutoReleaseGeometry geo;
1442
1443 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1444
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001445 bool hasTexCoords[GrPaint::kTotalStages] = {
1446 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1447 0 // remaining stages use positions
1448 };
1449
1450 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001451
1452 if (NULL != colors) {
1453 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001454 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001455 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001456
1457 if (sizeof(GrPoint) != vertexSize) {
1458 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001459 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460 return;
1461 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001462 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001464 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1465 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001466 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001467 NULL,
1468 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469 void* curVertex = geo.vertices();
1470
1471 for (int i = 0; i < vertexCount; ++i) {
1472 *((GrPoint*)curVertex) = positions[i];
1473
1474 if (texOffsets[0] > 0) {
1475 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1476 }
1477 if (colorOffset > 0) {
1478 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1479 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001480 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001481 }
1482 } else {
1483 target->setVertexSourceToArray(layout, positions, vertexCount);
1484 }
1485
bsalomon@google.com91958362011-06-13 17:58:13 +00001486 // we don't currently apply offscreen AA to this path. Need improved
1487 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001488
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001489 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001490 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001491 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001492 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001493 target->drawNonIndexed(primitiveType, 0, vertexCount);
1494 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001495}
1496
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001497///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498
reed@google.com07f3ee12011-05-16 17:21:57 +00001499void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1500 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001501
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001502 if (path.isEmpty()) {
1503#if GR_DEBUG
1504 GrPrintf("Empty path should have been caught by canvas.\n");
1505#endif
1506 if (GrIsFillInverted(fill)) {
1507 this->drawPaint(paint);
1508 }
1509 return;
1510 }
1511
bsalomon@google.com27847de2011-02-22 20:59:41 +00001512 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001513
bsalomon@google.com289533a2011-10-27 12:34:25 +00001514 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1515
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001516 // An Assumption here is that path renderer would use some form of tweaking
1517 // the src color (either the input alpha or in the frag shader) to implement
1518 // aa. If we have some future driver-mojo path AA that can do the right
1519 // thing WRT to the blend then we'll need some query on the PR.
1520 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001521#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001522 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001523#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001524 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001525 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001526
1527 bool doOSAA = false;
1528 GrPathRenderer* pr = NULL;
1529 if (prAA) {
1530 pr = this->getPathRenderer(path, fill, true);
1531 if (NULL == pr) {
1532 prAA = false;
1533 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1534 pr = this->getPathRenderer(path, fill, false);
1535 }
1536 } else {
1537 pr = this->getPathRenderer(path, fill, false);
1538 }
1539
bsalomon@google.com30085192011-08-19 15:42:31 +00001540 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001541#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001542 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001543#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001544 return;
1545 }
1546
bsalomon@google.com289533a2011-10-27 12:34:25 +00001547 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001548 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001549
bsalomon@google.com289533a2011-10-27 12:34:25 +00001550 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001551 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001552 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001553 // compute bounds as intersection of rt size, clip, and path
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001554 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001555 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001556 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001557 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001558 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001559 return;
1560 }
1561 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001562 GrRect pathBounds = path.getBounds();
1563 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001564 if (NULL != translate) {
1565 pathBounds.offset(*translate);
1566 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001567 target->getDrawState().getViewMatrix().mapRect(&pathBounds,
1568 pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001569 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001570 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001571 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001572 return;
1573 }
1574 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001575 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001576 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1577 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001578 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1579 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1580 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001581 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001582 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1583 }
1584 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001585 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001586 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001587 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1588 GrRect rect;
1589 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001590 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1591 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001592 target->drawSimpleRect(rect, NULL, stageMask);
1593 }
1594 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001595 rect.iset(clipIBounds.fLeft, bound.fTop,
1596 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001597 target->drawSimpleRect(rect, NULL, stageMask);
1598 }
1599 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001600 rect.iset(bound.fRight, bound.fTop,
1601 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001602 target->drawSimpleRect(rect, NULL, stageMask);
1603 }
1604 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001605 rect.iset(clipIBounds.fLeft, bound.fBottom,
1606 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001607 target->drawSimpleRect(rect, NULL, stageMask);
1608 }
1609 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001610 return;
1611 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001612 }
1613 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001615
bsalomon@google.com27847de2011-02-22 20:59:41 +00001616////////////////////////////////////////////////////////////////////////////////
1617
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001618bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001619 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001620}
1621
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001622void GrContext::flush(int flagsBitfield) {
1623 if (kDiscard_FlushBit & flagsBitfield) {
1624 fDrawBuffer->reset();
1625 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001626 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001627 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001628 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001629 fGpu->forceRenderTargetFlush();
1630 }
1631}
1632
1633void GrContext::flushText() {
1634 if (kText_DrawCategory == fLastDrawCategory) {
1635 flushDrawBuffer();
1636 }
1637}
1638
1639void GrContext::flushDrawBuffer() {
1640#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001641 if (fDrawBuffer) {
1642 fDrawBuffer->playback(fGpu);
1643 fDrawBuffer->reset();
1644 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001645#endif
1646}
1647
bsalomon@google.com6f379512011-11-16 20:36:03 +00001648void GrContext::internalWriteTexturePixels(GrTexture* texture,
1649 int left, int top,
1650 int width, int height,
1651 GrPixelConfig config,
1652 const void* buffer,
1653 size_t rowBytes,
1654 uint32_t flags) {
1655 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001656 ASSERT_OWNED_RESOURCE(texture);
1657
bsalomon@google.com6f379512011-11-16 20:36:03 +00001658 if (!(kDontFlush_PixelOpsFlag & flags)) {
1659 this->flush();
1660 }
1661 // TODO: use scratch texture to perform conversion
1662 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1663 GrPixelConfigIsUnpremultiplied(config)) {
1664 return;
1665 }
1666
1667 fGpu->writeTexturePixels(texture, left, top, width, height,
1668 config, buffer, rowBytes);
1669}
1670
1671bool GrContext::internalReadTexturePixels(GrTexture* texture,
1672 int left, int top,
1673 int width, int height,
1674 GrPixelConfig config,
1675 void* buffer,
1676 size_t rowBytes,
1677 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001678 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001679 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001680
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001681 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001682 GrRenderTarget* target = texture->asRenderTarget();
1683 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001684 return this->internalReadRenderTargetPixels(target,
1685 left, top, width, height,
1686 config, buffer, rowBytes,
1687 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001688 } else {
1689 return false;
1690 }
1691}
1692
bsalomon@google.com6f379512011-11-16 20:36:03 +00001693bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1694 int left, int top,
1695 int width, int height,
1696 GrPixelConfig config,
1697 void* buffer,
1698 size_t rowBytes,
1699 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001700 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001701 ASSERT_OWNED_RESOURCE(target);
1702
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001703 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001704 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001705 if (NULL == target) {
1706 return false;
1707 }
1708 }
1709
1710 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1711 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1712 // not supported at this time.
1713 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1714 !GrPixelConfigIsUnpremultiplied(config)) {
1715 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001716 }
1717
bsalomon@google.com6f379512011-11-16 20:36:03 +00001718 if (!(kDontFlush_PixelOpsFlag & flags)) {
1719 this->flush();
1720 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001721
1722 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001723 bool swapRAndB = NULL != src &&
1724 fGpu->preferredReadPixelsConfig(config) ==
1725 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001726
1727 bool flipY = NULL != src &&
1728 fGpu->readPixelsWillPayForYFlip(target, left, top,
1729 width, height, config,
1730 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001731 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1732 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001733
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001734 if (NULL == src && alphaConversion) {
1735 // we should fallback to cpu conversion here. This could happen when
1736 // we were given an external render target by the client that is not
1737 // also a texture (e.g. FBO 0 in GL)
1738 return false;
1739 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001740 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001741 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001742 if (flipY || swapRAndB || alphaConversion) {
1743 GrAssert(NULL != src);
1744 if (swapRAndB) {
1745 config = GrPixelConfigSwapRAndB(config);
1746 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001747 }
1748 // Make the scratch a render target because we don't have a robust
1749 // readTexturePixels as of yet (it calls this function).
1750 const GrTextureDesc desc = {
1751 kRenderTarget_GrTextureFlagBit,
1752 kNone_GrAALevel,
1753 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001754 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001755 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001756
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001757 // When a full readback is faster than a partial we could always make
1758 // the scratch exactly match the passed rect. However, if we see many
1759 // different size rectangles we will trash our texture cache and pay the
1760 // cost of creating and destroying many textures. So, we only request
1761 // an exact match when the caller is reading an entire RT.
1762 ScratchTexMatch match = kApprox_ScratchTexMatch;
1763 if (0 == left &&
1764 0 == top &&
1765 target->width() == width &&
1766 target->height() == height &&
1767 fGpu->fullReadPixelsIsFasterThanPartial()) {
1768 match = kExact_ScratchTexMatch;
1769 }
1770 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001771 GrTexture* texture = ast.texture();
1772 if (!texture) {
1773 return false;
1774 }
1775 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001776 GrAssert(NULL != target);
1777
1778 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001779 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001780 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001781 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001782
bsalomon@google.comc4364992011-11-07 15:54:49 +00001783 GrMatrix matrix;
1784 if (flipY) {
1785 matrix.setTranslate(SK_Scalar1 * left,
1786 SK_Scalar1 * (top + height));
1787 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1788 } else {
1789 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1790 }
1791 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001792 drawState->sampler(0)->reset(matrix);
1793 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001794 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001795 GrRect rect;
1796 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1797 fGpu->drawSimpleRect(rect, NULL, 0x1);
1798 left = 0;
1799 top = 0;
1800 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001801 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001802 left, top, width, height,
1803 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001804}
1805
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001806void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1807 if (NULL == src || NULL == dst) {
1808 return;
1809 }
1810 ASSERT_OWNED_RESOURCE(src);
1811
1812 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001813 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001814 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001815 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001816 GrMatrix sampleM;
1817 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001818 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001819 drawState->sampler(0)->reset(sampleM);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001820 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1821 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1822}
1823
bsalomon@google.com6f379512011-11-16 20:36:03 +00001824void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1825 int left, int top,
1826 int width, int height,
1827 GrPixelConfig config,
1828 const void* buffer,
1829 size_t rowBytes,
1830 uint32_t flags) {
1831 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001832 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001833
1834 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001835 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001836 if (NULL == target) {
1837 return;
1838 }
1839 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001840
1841 // TODO: when underlying api has a direct way to do this we should use it
1842 // (e.g. glDrawPixels on desktop GL).
1843
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001844 // If the RT is also a texture and we don't have to do PM/UPM conversion
1845 // then take the texture path, which we expect to be at least as fast or
1846 // faster since it doesn't use an intermediate texture as we do below.
1847
1848#if !GR_MAC_BUILD
1849 // At least some drivers on the Mac get confused when glTexImage2D is called
1850 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1851 // determine what OS versions and/or HW is affected.
1852 if (NULL != target->asTexture() &&
1853 GrPixelConfigIsUnpremultiplied(target->config()) ==
1854 GrPixelConfigIsUnpremultiplied(config)) {
1855
1856 this->internalWriteTexturePixels(target->asTexture(),
1857 left, top, width, height,
1858 config, buffer, rowBytes, flags);
1859 return;
1860 }
1861#endif
1862
1863 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1864 GrPixelConfigSwapRAndB(config);
1865 if (swapRAndB) {
1866 config = GrPixelConfigSwapRAndB(config);
1867 }
1868
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001869 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001870 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001871 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001872 GrAutoScratchTexture ast(this, desc);
1873 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001874 if (NULL == texture) {
1875 return;
1876 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001877 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1878 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001879
bsalomon@google.com27847de2011-02-22 20:59:41 +00001880 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001881 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001882 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001883
1884 GrMatrix matrix;
1885 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001886 drawState->setViewMatrix(matrix);
1887 drawState->setRenderTarget(target);
1888 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889
bsalomon@google.com5c638652011-07-18 19:31:59 +00001890 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001891 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1892 GrSamplerState::kNearest_Filter,
1893 matrix);
1894 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001895
1896 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1897 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001898 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001899 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1900 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001901 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001902 return;
1903 }
1904 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1905 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1906}
1907////////////////////////////////////////////////////////////////////////////////
1908
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001909void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001910 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001911
1912 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1913 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001914 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001915 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001916 if (paint.getTexture(i)) {
1917 *drawState->sampler(s) = paint.getTextureSampler(i);
1918 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001919 }
1920
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001921 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001922
1923 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1924 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001925 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001926 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001927 if (paint.getMask(i)) {
1928 *drawState->sampler(s) = paint.getMaskSampler(i);
1929 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001930 }
1931
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001932 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001933
1934 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001935 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001936 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001937 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938 }
1939 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001940 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001941 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001942 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001943 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001944 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001945 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001946
1947 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1948 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1949 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001950}
1951
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001952GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001953 DrawCategory category) {
1954 if (category != fLastDrawCategory) {
1955 flushDrawBuffer();
1956 fLastDrawCategory = category;
1957 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001958 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001959 GrDrawTarget* target = fGpu;
1960 switch (category) {
1961 case kText_DrawCategory:
1962#if DEFER_TEXT_RENDERING
1963 target = fDrawBuffer;
1964 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1965#else
1966 target = fGpu;
1967#endif
1968 break;
1969 case kUnbuffered_DrawCategory:
1970 target = fGpu;
1971 break;
1972 case kBuffered_DrawCategory:
1973 target = fDrawBuffer;
1974 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1975 break;
1976 }
1977 return target;
1978}
1979
bsalomon@google.com289533a2011-10-27 12:34:25 +00001980GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1981 GrPathFill fill,
1982 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001983 if (NULL == fPathRendererChain) {
1984 fPathRendererChain =
1985 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1986 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001987 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1988 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001989}
1990
bsalomon@google.com27847de2011-02-22 20:59:41 +00001991////////////////////////////////////////////////////////////////////////////////
1992
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001994 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001995 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001996 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001997}
1998
1999GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002000 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002001}
2002
2003const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002004 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002005}
2006
2007const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002008 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002009}
2010
2011void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002012 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002013}
2014
2015void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002016 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002017}
2018
2019static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2020 intptr_t mask = 1 << shift;
2021 if (pred) {
2022 bits |= mask;
2023 } else {
2024 bits &= ~mask;
2025 }
2026 return bits;
2027}
2028
2029void GrContext::resetStats() {
2030 fGpu->resetStats();
2031}
2032
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002033const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002034 return fGpu->getStats();
2035}
2036
2037void GrContext::printStats() const {
2038 fGpu->printStats();
2039}
2040
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002041GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002042 fGpu = gpu;
2043 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002044 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002045
bsalomon@google.com30085192011-08-19 15:42:31 +00002046 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002047
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002048 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2049 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002050 fFontCache = new GrFontCache(fGpu);
2051
2052 fLastDrawCategory = kUnbuffered_DrawCategory;
2053
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002054 fDrawBuffer = NULL;
2055 fDrawBufferVBAllocPool = NULL;
2056 fDrawBufferIBAllocPool = NULL;
2057
bsalomon@google.com205d4602011-04-25 12:43:45 +00002058 fAAFillRectIndexBuffer = NULL;
2059 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002060
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002061 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2062 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002063 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2064 }
2065 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002066
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002067 this->setupDrawBuffer();
2068}
2069
2070void GrContext::setupDrawBuffer() {
2071
2072 GrAssert(NULL == fDrawBuffer);
2073 GrAssert(NULL == fDrawBufferVBAllocPool);
2074 GrAssert(NULL == fDrawBufferIBAllocPool);
2075
bsalomon@google.com27847de2011-02-22 20:59:41 +00002076#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002077 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002078 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002079 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2080 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002081 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002082 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002083 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002084 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2085
bsalomon@google.com471d4712011-08-23 15:45:25 +00002086 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2087 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002088 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002089#endif
2090
2091#if BATCH_RECT_TO_RECT
2092 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2093#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002094}
2095
bsalomon@google.com27847de2011-02-22 20:59:41 +00002096GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2097 GrDrawTarget* target;
2098#if DEFER_TEXT_RENDERING
2099 target = prepareToDraw(paint, kText_DrawCategory);
2100#else
2101 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2102#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002103 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002104 return target;
2105}
2106
2107const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2108 return fGpu->getQuadIndexBuffer();
2109}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002110
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002111void GrContext::convolveInX(GrTexture* texture,
2112 const SkRect& rect,
2113 const float* kernel,
2114 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002115 ASSERT_OWNED_RESOURCE(texture);
2116
bsalomon@google.com99621082011-11-15 16:47:16 +00002117 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002118 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2119}
2120
2121void GrContext::convolveInY(GrTexture* texture,
2122 const SkRect& rect,
2123 const float* kernel,
2124 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002125 ASSERT_OWNED_RESOURCE(texture);
2126
bsalomon@google.com99621082011-11-15 16:47:16 +00002127 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002128 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2129}
2130
2131void GrContext::convolve(GrTexture* texture,
2132 const SkRect& rect,
2133 float imageIncrement[2],
2134 const float* kernel,
2135 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002136 ASSERT_OWNED_RESOURCE(texture);
2137
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002138 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002139 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002140 GrMatrix sampleM;
2141 sampleM.setIDiv(texture->width(), texture->height());
2142 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2143 GrSamplerState::kConvolution_Filter,
2144 sampleM);
2145 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2146 kernel,
2147 imageIncrement);
2148
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002149 drawState->setViewMatrix(GrMatrix::I());
2150 drawState->setTexture(0, texture);
2151 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002152 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002153 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2154}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002155
2156///////////////////////////////////////////////////////////////////////////////