blob: 4e0e587c2a444f8287f4ecc52ca0e71ff766bc72 [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.coma47a48d2011-04-26 20:22:11 +0000871 GrMatrix sampleM;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000873 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000874 int scale;
875
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000876 enum {
877 kOffscreenStage = GrPaint::kTotalStages,
878 };
879
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000880 GrDrawState* drawState = target->drawState();
881
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000882 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000883 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000884 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000885 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000886
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000887 // Do 2x2 downsample from first to second
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000888 drawState->setTexture(kOffscreenStage, src);
889 drawState->setRenderTarget(dst);
890 drawState->setViewMatrix(GrMatrix::I());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000891 sampleM.setScale(scale * GR_Scalar1 / src->width(),
892 scale * GR_Scalar1 / src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000893 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
894 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
895 sampler->setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000896 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
897 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000898 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
899
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000900 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000901 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000902 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000903 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000904 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000905 } else {
906 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
907 record->fDownsample);
908 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000909 }
910
bsalomon@google.com91958362011-06-13 17:58:13 +0000911 // setup for draw back to main RT, we use the original
912 // draw state setup by the caller plus an additional coverage
913 // stage to handle the AA resolve. Also, we use an identity
914 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000915 int stageMask = paint.getActiveStageMask();
916
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000917 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000918 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000919
920 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000921 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000922 if (drawState->getViewInverse(&invVM)) {
923 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000924 }
925 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000926 // This is important when tiling, otherwise second tile's
927 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000928 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000929
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000930 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000931 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
932 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000933 sampleM.setScale(scale * GR_Scalar1 / src->width(),
934 scale * GR_Scalar1 / src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000935
936 sampler->setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000937 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
938 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000939 sampler->preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000940
reed@google.com20efde72011-05-09 17:00:02 +0000941 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000942 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000943 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000944 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000945}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000946
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000947void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
948 GrPathRenderer* pr,
949 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000950 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000951}
952
953////////////////////////////////////////////////////////////////////////////////
954
bsalomon@google.com27847de2011-02-22 20:59:41 +0000955/* create a triangle strip that strokes the specified triangle. There are 8
956 unique vertices, but we repreat the last 2 to close up. Alternatively we
957 could use an indices array, and then only send 8 verts, but not sure that
958 would be faster.
959 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000960static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000961 GrScalar width) {
962 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000963 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000964
965 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
966 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
967 verts[2].set(rect.fRight - rad, rect.fTop + rad);
968 verts[3].set(rect.fRight + rad, rect.fTop - rad);
969 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
970 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
971 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
972 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
973 verts[8] = verts[0];
974 verts[9] = verts[1];
975}
976
bsalomon@google.com205d4602011-04-25 12:43:45 +0000977static void setInsetFan(GrPoint* pts, size_t stride,
978 const GrRect& r, GrScalar dx, GrScalar dy) {
979 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
980}
981
982static const uint16_t gFillAARectIdx[] = {
983 0, 1, 5, 5, 4, 0,
984 1, 2, 6, 6, 5, 1,
985 2, 3, 7, 7, 6, 2,
986 3, 0, 4, 4, 7, 3,
987 4, 5, 6, 6, 7, 4,
988};
989
990int GrContext::aaFillRectIndexCount() const {
991 return GR_ARRAY_COUNT(gFillAARectIdx);
992}
993
994GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
995 if (NULL == fAAFillRectIndexBuffer) {
996 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
997 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000998 if (NULL != fAAFillRectIndexBuffer) {
999 #if GR_DEBUG
1000 bool updated =
1001 #endif
1002 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
1003 sizeof(gFillAARectIdx));
1004 GR_DEBUGASSERT(updated);
1005 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001006 }
1007 return fAAFillRectIndexBuffer;
1008}
1009
1010static const uint16_t gStrokeAARectIdx[] = {
1011 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
1012 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1013 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1014 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1015
1016 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1017 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1018 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1019 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1020
1021 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1022 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1023 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1024 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1025};
1026
1027int GrContext::aaStrokeRectIndexCount() const {
1028 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1029}
1030
1031GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1032 if (NULL == fAAStrokeRectIndexBuffer) {
1033 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1034 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001035 if (NULL != fAAStrokeRectIndexBuffer) {
1036 #if GR_DEBUG
1037 bool updated =
1038 #endif
1039 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1040 sizeof(gStrokeAARectIdx));
1041 GR_DEBUGASSERT(updated);
1042 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001043 }
1044 return fAAStrokeRectIndexBuffer;
1045}
1046
bsalomon@google.coma3108262011-10-10 14:08:47 +00001047static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1048 bool useCoverage) {
1049 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001050 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001051 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001052 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1053 }
1054 }
1055 if (useCoverage) {
1056 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1057 } else {
1058 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1059 }
1060 return layout;
1061}
1062
bsalomon@google.com205d4602011-04-25 12:43:45 +00001063void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001064 const GrRect& devRect,
1065 bool useVertexCoverage) {
1066 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001067
1068 size_t vsize = GrDrawTarget::VertexSize(layout);
1069
1070 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001071 if (!geo.succeeded()) {
1072 GrPrintf("Failed to get space for vertices!\n");
1073 return;
1074 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001075 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1076 if (NULL == indexBuffer) {
1077 GrPrintf("Failed to create index buffer!\n");
1078 return;
1079 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001080
1081 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1082
1083 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1084 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1085
1086 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1087 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1088
1089 verts += sizeof(GrPoint);
1090 for (int i = 0; i < 4; ++i) {
1091 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1092 }
1093
bsalomon@google.coma3108262011-10-10 14:08:47 +00001094 GrColor innerColor;
1095 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001096 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001097 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001098 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001099 }
1100
bsalomon@google.com205d4602011-04-25 12:43:45 +00001101 verts += 4 * vsize;
1102 for (int i = 0; i < 4; ++i) {
1103 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1104 }
1105
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001106 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001107
1108 target->drawIndexed(kTriangles_PrimitiveType, 0,
1109 0, 8, this->aaFillRectIndexCount());
1110}
1111
bsalomon@google.coma3108262011-10-10 14:08:47 +00001112void GrContext::strokeAARect(GrDrawTarget* target,
1113 const GrRect& devRect,
1114 const GrVec& devStrokeSize,
1115 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001116 const GrScalar& dx = devStrokeSize.fX;
1117 const GrScalar& dy = devStrokeSize.fY;
1118 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1119 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1120
bsalomon@google.com205d4602011-04-25 12:43:45 +00001121 GrScalar spare;
1122 {
1123 GrScalar w = devRect.width() - dx;
1124 GrScalar h = devRect.height() - dy;
1125 spare = GrMin(w, h);
1126 }
1127
1128 if (spare <= 0) {
1129 GrRect r(devRect);
1130 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001131 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001132 return;
1133 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001134 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001135 size_t vsize = GrDrawTarget::VertexSize(layout);
1136
1137 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001138 if (!geo.succeeded()) {
1139 GrPrintf("Failed to get space for vertices!\n");
1140 return;
1141 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001142 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1143 if (NULL == indexBuffer) {
1144 GrPrintf("Failed to create index buffer!\n");
1145 return;
1146 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001147
1148 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1149
1150 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1151 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1152 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1153 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1154
1155 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1156 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1157 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1158 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1159
1160 verts += sizeof(GrPoint);
1161 for (int i = 0; i < 4; ++i) {
1162 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1163 }
1164
bsalomon@google.coma3108262011-10-10 14:08:47 +00001165 GrColor innerColor;
1166 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001167 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001168 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001169 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001170 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001171 verts += 4 * vsize;
1172 for (int i = 0; i < 8; ++i) {
1173 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1174 }
1175
1176 verts += 8 * vsize;
1177 for (int i = 0; i < 8; ++i) {
1178 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1179 }
1180
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001181 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001182 target->drawIndexed(kTriangles_PrimitiveType,
1183 0, 0, 16, aaStrokeRectIndexCount());
1184}
1185
reed@google.com20efde72011-05-09 17:00:02 +00001186/**
1187 * Returns true if the rects edges are integer-aligned.
1188 */
1189static bool isIRect(const GrRect& r) {
1190 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1191 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1192}
1193
bsalomon@google.com205d4602011-04-25 12:43:45 +00001194static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001195 const GrRect& rect,
1196 GrScalar width,
1197 const GrMatrix* matrix,
1198 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001199 GrRect* devRect,
1200 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001201 // we use a simple alpha ramp to do aa on axis-aligned rects
1202 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001203 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001204
bsalomon@google.coma3108262011-10-10 14:08:47 +00001205 // we are keeping around the "tweak the alpha" trick because
1206 // it is our only hope for the fixed-pipe implementation.
1207 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001208 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001209 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001210 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001211 if (target->getCaps().fSupportPerVertexCoverage) {
1212 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001213#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001214 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001215#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001216 return false;
1217 } else {
1218 *useVertexCoverage = true;
1219 }
1220 } else {
1221 GrPrintf("Rect AA dropped because no support for coverage.\n");
1222 return false;
1223 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001224 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001225 const GrDrawState& drawState = target->getDrawState();
1226 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001227 return false;
1228 }
1229
bsalomon@google.com471d4712011-08-23 15:45:25 +00001230 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001231 return false;
1232 }
1233
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001234 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001235 return false;
1236 }
1237
1238 if (NULL != matrix &&
1239 !matrix->preservesAxisAlignment()) {
1240 return false;
1241 }
1242
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001243 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001244 if (NULL != matrix) {
1245 combinedMatrix->preConcat(*matrix);
1246 GrAssert(combinedMatrix->preservesAxisAlignment());
1247 }
1248
1249 combinedMatrix->mapRect(devRect, rect);
1250 devRect->sort();
1251
1252 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001253 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001254 } else {
1255 return true;
1256 }
1257}
1258
bsalomon@google.com27847de2011-02-22 20:59:41 +00001259void GrContext::drawRect(const GrPaint& paint,
1260 const GrRect& rect,
1261 GrScalar width,
1262 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001263 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001264
1265 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001266 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001267
bsalomon@google.com205d4602011-04-25 12:43:45 +00001268 GrRect devRect = rect;
1269 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001270 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001271 bool needAA = paint.fAntiAlias &&
1272 !this->getRenderTarget()->isMultisampled();
1273 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1274 &combinedMatrix, &devRect,
1275 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001276
1277 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001278 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001279 if (width >= 0) {
1280 GrVec strokeSize;;
1281 if (width > 0) {
1282 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001283 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001284 strokeSize.setAbs(strokeSize);
1285 } else {
1286 strokeSize.set(GR_Scalar1, GR_Scalar1);
1287 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001288 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001289 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001290 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001291 }
1292 return;
1293 }
1294
bsalomon@google.com27847de2011-02-22 20:59:41 +00001295 if (width >= 0) {
1296 // TODO: consider making static vertex buffers for these cases.
1297 // Hairline could be done by just adding closing vertex to
1298 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001299 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1300
bsalomon@google.com27847de2011-02-22 20:59:41 +00001301 static const int worstCaseVertCount = 10;
1302 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1303
1304 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001305 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001306 return;
1307 }
1308
1309 GrPrimitiveType primType;
1310 int vertCount;
1311 GrPoint* vertex = geo.positions();
1312
1313 if (width > 0) {
1314 vertCount = 10;
1315 primType = kTriangleStrip_PrimitiveType;
1316 setStrokeRectStrip(vertex, rect, width);
1317 } else {
1318 // hairline
1319 vertCount = 5;
1320 primType = kLineStrip_PrimitiveType;
1321 vertex[0].set(rect.fLeft, rect.fTop);
1322 vertex[1].set(rect.fRight, rect.fTop);
1323 vertex[2].set(rect.fRight, rect.fBottom);
1324 vertex[3].set(rect.fLeft, rect.fBottom);
1325 vertex[4].set(rect.fLeft, rect.fTop);
1326 }
1327
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001328 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001329 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001330 GrDrawState* drawState = target->drawState();
1331 avmr.set(drawState);
1332 drawState->preConcatViewMatrix(*matrix);
1333 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001334 }
1335
1336 target->drawNonIndexed(primType, 0, vertCount);
1337 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001338#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001339 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001340 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1341 if (NULL == sqVB) {
1342 GrPrintf("Failed to create static rect vb.\n");
1343 return;
1344 }
1345 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001346 GrDrawState* drawState = target->drawState();
1347 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001348 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001349 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001350 0, rect.height(), rect.fTop,
1351 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001352
1353 if (NULL != matrix) {
1354 m.postConcat(*matrix);
1355 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001356 drawState->preConcatViewMatrix(m);
1357 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001358
bsalomon@google.com27847de2011-02-22 20:59:41 +00001359 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001360#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001361 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001362#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001363 }
1364}
1365
1366void GrContext::drawRectToRect(const GrPaint& paint,
1367 const GrRect& dstRect,
1368 const GrRect& srcRect,
1369 const GrMatrix* dstMatrix,
1370 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001371 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001373 // srcRect refers to paint's first texture
1374 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001375 drawRect(paint, dstRect, -1, dstMatrix);
1376 return;
1377 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001378
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1380
1381#if GR_STATIC_RECT_VB
1382 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001383 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001384 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001385 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001386
1387 GrMatrix m;
1388
1389 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1390 0, dstRect.height(), dstRect.fTop,
1391 0, 0, GrMatrix::I()[8]);
1392 if (NULL != dstMatrix) {
1393 m.postConcat(*dstMatrix);
1394 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001395 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001396
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001397 // srcRect refers to first stage
1398 int otherStageMask = paint.getActiveStageMask() &
1399 (~(1 << GrPaint::kFirstTextureStage));
1400 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001401 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001402 }
1403
bsalomon@google.com27847de2011-02-22 20:59:41 +00001404 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1405 0, srcRect.height(), srcRect.fTop,
1406 0, 0, GrMatrix::I()[8]);
1407 if (NULL != srcMatrix) {
1408 m.postConcat(*srcMatrix);
1409 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001410 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001412 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1413 if (NULL == sqVB) {
1414 GrPrintf("Failed to create static rect vb.\n");
1415 return;
1416 }
1417 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001418 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1419#else
1420
1421 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001422#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001424#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001425 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1426#endif
1427
tomhudson@google.com93813632011-10-27 20:21:16 +00001428 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1429 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001430 srcRects[0] = &srcRect;
1431 srcMatrices[0] = srcMatrix;
1432
1433 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1434#endif
1435}
1436
1437void GrContext::drawVertices(const GrPaint& paint,
1438 GrPrimitiveType primitiveType,
1439 int vertexCount,
1440 const GrPoint positions[],
1441 const GrPoint texCoords[],
1442 const GrColor colors[],
1443 const uint16_t indices[],
1444 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001445 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001446
1447 GrDrawTarget::AutoReleaseGeometry geo;
1448
1449 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1450
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001451 bool hasTexCoords[GrPaint::kTotalStages] = {
1452 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1453 0 // remaining stages use positions
1454 };
1455
1456 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001457
1458 if (NULL != colors) {
1459 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001461 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001462
1463 if (sizeof(GrPoint) != vertexSize) {
1464 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001465 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466 return;
1467 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001468 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001470 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1471 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001472 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001473 NULL,
1474 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001475 void* curVertex = geo.vertices();
1476
1477 for (int i = 0; i < vertexCount; ++i) {
1478 *((GrPoint*)curVertex) = positions[i];
1479
1480 if (texOffsets[0] > 0) {
1481 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1482 }
1483 if (colorOffset > 0) {
1484 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1485 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001486 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001487 }
1488 } else {
1489 target->setVertexSourceToArray(layout, positions, vertexCount);
1490 }
1491
bsalomon@google.com91958362011-06-13 17:58:13 +00001492 // we don't currently apply offscreen AA to this path. Need improved
1493 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001494
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001495 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001496 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001497 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001499 target->drawNonIndexed(primitiveType, 0, vertexCount);
1500 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001501}
1502
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001503///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001504
reed@google.com07f3ee12011-05-16 17:21:57 +00001505void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1506 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001507
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001508 if (path.isEmpty()) {
1509#if GR_DEBUG
1510 GrPrintf("Empty path should have been caught by canvas.\n");
1511#endif
1512 if (GrIsFillInverted(fill)) {
1513 this->drawPaint(paint);
1514 }
1515 return;
1516 }
1517
bsalomon@google.com27847de2011-02-22 20:59:41 +00001518 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001519
bsalomon@google.com289533a2011-10-27 12:34:25 +00001520 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1521
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001522 // An Assumption here is that path renderer would use some form of tweaking
1523 // the src color (either the input alpha or in the frag shader) to implement
1524 // aa. If we have some future driver-mojo path AA that can do the right
1525 // thing WRT to the blend then we'll need some query on the PR.
1526 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001527#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001528 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001529#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001530 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001531 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001532
1533 bool doOSAA = false;
1534 GrPathRenderer* pr = NULL;
1535 if (prAA) {
1536 pr = this->getPathRenderer(path, fill, true);
1537 if (NULL == pr) {
1538 prAA = false;
1539 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1540 pr = this->getPathRenderer(path, fill, false);
1541 }
1542 } else {
1543 pr = this->getPathRenderer(path, fill, false);
1544 }
1545
bsalomon@google.com30085192011-08-19 15:42:31 +00001546 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001547#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001548 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001549#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001550 return;
1551 }
1552
bsalomon@google.com289533a2011-10-27 12:34:25 +00001553 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001554 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001555
bsalomon@google.com289533a2011-10-27 12:34:25 +00001556 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001557 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001558 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001559 // compute bounds as intersection of rt size, clip, and path
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001560 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001561 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001562 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001563 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001564 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001565 return;
1566 }
1567 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001568 GrRect pathBounds = path.getBounds();
1569 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001570 if (NULL != translate) {
1571 pathBounds.offset(*translate);
1572 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001573 target->getDrawState().getViewMatrix().mapRect(&pathBounds,
1574 pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001575 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001576 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001577 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001578 return;
1579 }
1580 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001581 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001582 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1583 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001584 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1585 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1586 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001587 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001588 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1589 }
1590 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001591 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001592 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001593 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1594 GrRect rect;
1595 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001596 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1597 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001598 target->drawSimpleRect(rect, NULL, stageMask);
1599 }
1600 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001601 rect.iset(clipIBounds.fLeft, bound.fTop,
1602 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001603 target->drawSimpleRect(rect, NULL, stageMask);
1604 }
1605 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001606 rect.iset(bound.fRight, bound.fTop,
1607 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001608 target->drawSimpleRect(rect, NULL, stageMask);
1609 }
1610 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001611 rect.iset(clipIBounds.fLeft, bound.fBottom,
1612 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001613 target->drawSimpleRect(rect, NULL, stageMask);
1614 }
1615 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001616 return;
1617 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001618 }
1619 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001620}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001621
bsalomon@google.com27847de2011-02-22 20:59:41 +00001622////////////////////////////////////////////////////////////////////////////////
1623
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001624bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001625 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001626}
1627
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001628void GrContext::flush(int flagsBitfield) {
1629 if (kDiscard_FlushBit & flagsBitfield) {
1630 fDrawBuffer->reset();
1631 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001632 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001633 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001634 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001635 fGpu->forceRenderTargetFlush();
1636 }
1637}
1638
1639void GrContext::flushText() {
1640 if (kText_DrawCategory == fLastDrawCategory) {
1641 flushDrawBuffer();
1642 }
1643}
1644
1645void GrContext::flushDrawBuffer() {
1646#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001647 if (fDrawBuffer) {
1648 fDrawBuffer->playback(fGpu);
1649 fDrawBuffer->reset();
1650 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001651#endif
1652}
1653
bsalomon@google.com6f379512011-11-16 20:36:03 +00001654void GrContext::internalWriteTexturePixels(GrTexture* texture,
1655 int left, int top,
1656 int width, int height,
1657 GrPixelConfig config,
1658 const void* buffer,
1659 size_t rowBytes,
1660 uint32_t flags) {
1661 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001662 ASSERT_OWNED_RESOURCE(texture);
1663
bsalomon@google.com6f379512011-11-16 20:36:03 +00001664 if (!(kDontFlush_PixelOpsFlag & flags)) {
1665 this->flush();
1666 }
1667 // TODO: use scratch texture to perform conversion
1668 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1669 GrPixelConfigIsUnpremultiplied(config)) {
1670 return;
1671 }
1672
1673 fGpu->writeTexturePixels(texture, left, top, width, height,
1674 config, buffer, rowBytes);
1675}
1676
1677bool GrContext::internalReadTexturePixels(GrTexture* texture,
1678 int left, int top,
1679 int width, int height,
1680 GrPixelConfig config,
1681 void* buffer,
1682 size_t rowBytes,
1683 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001684 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001685 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001686
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001687 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001688 GrRenderTarget* target = texture->asRenderTarget();
1689 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001690 return this->internalReadRenderTargetPixels(target,
1691 left, top, width, height,
1692 config, buffer, rowBytes,
1693 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001694 } else {
1695 return false;
1696 }
1697}
1698
bsalomon@google.com6f379512011-11-16 20:36:03 +00001699bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1700 int left, int top,
1701 int width, int height,
1702 GrPixelConfig config,
1703 void* buffer,
1704 size_t rowBytes,
1705 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001706 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001707 ASSERT_OWNED_RESOURCE(target);
1708
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001709 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001710 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001711 if (NULL == target) {
1712 return false;
1713 }
1714 }
1715
1716 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1717 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1718 // not supported at this time.
1719 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1720 !GrPixelConfigIsUnpremultiplied(config)) {
1721 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001722 }
1723
bsalomon@google.com6f379512011-11-16 20:36:03 +00001724 if (!(kDontFlush_PixelOpsFlag & flags)) {
1725 this->flush();
1726 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001727
1728 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001729 bool swapRAndB = NULL != src &&
1730 fGpu->preferredReadPixelsConfig(config) ==
1731 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001732
1733 bool flipY = NULL != src &&
1734 fGpu->readPixelsWillPayForYFlip(target, left, top,
1735 width, height, config,
1736 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001737 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1738 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001739
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001740 if (NULL == src && alphaConversion) {
1741 // we should fallback to cpu conversion here. This could happen when
1742 // we were given an external render target by the client that is not
1743 // also a texture (e.g. FBO 0 in GL)
1744 return false;
1745 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001746 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001747 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001748 if (flipY || swapRAndB || alphaConversion) {
1749 GrAssert(NULL != src);
1750 if (swapRAndB) {
1751 config = GrPixelConfigSwapRAndB(config);
1752 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001753 }
1754 // Make the scratch a render target because we don't have a robust
1755 // readTexturePixels as of yet (it calls this function).
1756 const GrTextureDesc desc = {
1757 kRenderTarget_GrTextureFlagBit,
1758 kNone_GrAALevel,
1759 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001760 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001761 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001762
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001763 // When a full readback is faster than a partial we could always make
1764 // the scratch exactly match the passed rect. However, if we see many
1765 // different size rectangles we will trash our texture cache and pay the
1766 // cost of creating and destroying many textures. So, we only request
1767 // an exact match when the caller is reading an entire RT.
1768 ScratchTexMatch match = kApprox_ScratchTexMatch;
1769 if (0 == left &&
1770 0 == top &&
1771 target->width() == width &&
1772 target->height() == height &&
1773 fGpu->fullReadPixelsIsFasterThanPartial()) {
1774 match = kExact_ScratchTexMatch;
1775 }
1776 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001777 GrTexture* texture = ast.texture();
1778 if (!texture) {
1779 return false;
1780 }
1781 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001782 GrAssert(NULL != target);
1783
1784 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001785 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001786 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001787 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001788
bsalomon@google.comc4364992011-11-07 15:54:49 +00001789 GrMatrix matrix;
1790 if (flipY) {
1791 matrix.setTranslate(SK_Scalar1 * left,
1792 SK_Scalar1 * (top + height));
1793 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1794 } else {
1795 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1796 }
1797 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001798 drawState->sampler(0)->reset(matrix);
1799 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001800 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001801 GrRect rect;
1802 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1803 fGpu->drawSimpleRect(rect, NULL, 0x1);
1804 left = 0;
1805 top = 0;
1806 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001807 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001808 left, top, width, height,
1809 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001810}
1811
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001812void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1813 if (NULL == src || NULL == dst) {
1814 return;
1815 }
1816 ASSERT_OWNED_RESOURCE(src);
1817
1818 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001819 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001820 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001821 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001822 GrMatrix sampleM;
1823 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001824 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001825 drawState->sampler(0)->reset(sampleM);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001826 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1827 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1828}
1829
bsalomon@google.com6f379512011-11-16 20:36:03 +00001830void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1831 int left, int top,
1832 int width, int height,
1833 GrPixelConfig config,
1834 const void* buffer,
1835 size_t rowBytes,
1836 uint32_t flags) {
1837 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001838 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001839
1840 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001841 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001842 if (NULL == target) {
1843 return;
1844 }
1845 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001846
1847 // TODO: when underlying api has a direct way to do this we should use it
1848 // (e.g. glDrawPixels on desktop GL).
1849
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001850 // If the RT is also a texture and we don't have to do PM/UPM conversion
1851 // then take the texture path, which we expect to be at least as fast or
1852 // faster since it doesn't use an intermediate texture as we do below.
1853
1854#if !GR_MAC_BUILD
1855 // At least some drivers on the Mac get confused when glTexImage2D is called
1856 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1857 // determine what OS versions and/or HW is affected.
1858 if (NULL != target->asTexture() &&
1859 GrPixelConfigIsUnpremultiplied(target->config()) ==
1860 GrPixelConfigIsUnpremultiplied(config)) {
1861
1862 this->internalWriteTexturePixels(target->asTexture(),
1863 left, top, width, height,
1864 config, buffer, rowBytes, flags);
1865 return;
1866 }
1867#endif
1868
1869 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1870 GrPixelConfigSwapRAndB(config);
1871 if (swapRAndB) {
1872 config = GrPixelConfigSwapRAndB(config);
1873 }
1874
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001875 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001876 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001877 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001878 GrAutoScratchTexture ast(this, desc);
1879 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001880 if (NULL == texture) {
1881 return;
1882 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001883 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1884 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001885
bsalomon@google.com27847de2011-02-22 20:59:41 +00001886 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001887 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001888 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889
1890 GrMatrix matrix;
1891 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001892 drawState->setViewMatrix(matrix);
1893 drawState->setRenderTarget(target);
1894 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001895
bsalomon@google.com5c638652011-07-18 19:31:59 +00001896 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001897 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1898 GrSamplerState::kNearest_Filter,
1899 matrix);
1900 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001901
1902 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1903 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001904 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001905 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1906 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001907 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001908 return;
1909 }
1910 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1911 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1912}
1913////////////////////////////////////////////////////////////////////////////////
1914
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001915void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001916 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001917
1918 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1919 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001920 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001921 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001922 *drawState->sampler(s) = paint.getTextureSampler(i);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001923 }
1924
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001925 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001926
1927 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1928 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001929 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001930 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001931 *drawState->sampler(s) = paint.getMaskSampler(i);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001932 }
1933
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001934 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001935
1936 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001937 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001939 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001940 }
1941 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001942 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001943 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001944 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001945 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001946 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001947 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001948
1949 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1950 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1951 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001952}
1953
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001954GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001955 DrawCategory category) {
1956 if (category != fLastDrawCategory) {
1957 flushDrawBuffer();
1958 fLastDrawCategory = category;
1959 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001960 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001961 GrDrawTarget* target = fGpu;
1962 switch (category) {
1963 case kText_DrawCategory:
1964#if DEFER_TEXT_RENDERING
1965 target = fDrawBuffer;
1966 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1967#else
1968 target = fGpu;
1969#endif
1970 break;
1971 case kUnbuffered_DrawCategory:
1972 target = fGpu;
1973 break;
1974 case kBuffered_DrawCategory:
1975 target = fDrawBuffer;
1976 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1977 break;
1978 }
1979 return target;
1980}
1981
bsalomon@google.com289533a2011-10-27 12:34:25 +00001982GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1983 GrPathFill fill,
1984 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001985 if (NULL == fPathRendererChain) {
1986 fPathRendererChain =
1987 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1988 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001989 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1990 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001991}
1992
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993////////////////////////////////////////////////////////////////////////////////
1994
bsalomon@google.com27847de2011-02-22 20:59:41 +00001995void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001996 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001997 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001998 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001999}
2000
2001GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002002 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002003}
2004
2005const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002006 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002007}
2008
2009const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002010 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002011}
2012
2013void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002014 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002015}
2016
2017void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002018 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002019}
2020
2021static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2022 intptr_t mask = 1 << shift;
2023 if (pred) {
2024 bits |= mask;
2025 } else {
2026 bits &= ~mask;
2027 }
2028 return bits;
2029}
2030
2031void GrContext::resetStats() {
2032 fGpu->resetStats();
2033}
2034
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002035const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002036 return fGpu->getStats();
2037}
2038
2039void GrContext::printStats() const {
2040 fGpu->printStats();
2041}
2042
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002043GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002044 fGpu = gpu;
2045 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002046 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002047
bsalomon@google.com30085192011-08-19 15:42:31 +00002048 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002049
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002050 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2051 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002052 fFontCache = new GrFontCache(fGpu);
2053
2054 fLastDrawCategory = kUnbuffered_DrawCategory;
2055
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002056 fDrawBuffer = NULL;
2057 fDrawBufferVBAllocPool = NULL;
2058 fDrawBufferIBAllocPool = NULL;
2059
bsalomon@google.com205d4602011-04-25 12:43:45 +00002060 fAAFillRectIndexBuffer = NULL;
2061 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002062
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002063 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2064 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002065 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2066 }
2067 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002068
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002069 this->setupDrawBuffer();
2070}
2071
2072void GrContext::setupDrawBuffer() {
2073
2074 GrAssert(NULL == fDrawBuffer);
2075 GrAssert(NULL == fDrawBufferVBAllocPool);
2076 GrAssert(NULL == fDrawBufferIBAllocPool);
2077
bsalomon@google.com27847de2011-02-22 20:59:41 +00002078#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002079 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002080 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002081 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2082 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002083 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002084 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002085 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002086 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2087
bsalomon@google.com471d4712011-08-23 15:45:25 +00002088 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2089 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002090 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002091#endif
2092
2093#if BATCH_RECT_TO_RECT
2094 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2095#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002096}
2097
bsalomon@google.com27847de2011-02-22 20:59:41 +00002098GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2099 GrDrawTarget* target;
2100#if DEFER_TEXT_RENDERING
2101 target = prepareToDraw(paint, kText_DrawCategory);
2102#else
2103 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2104#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002105 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002106 return target;
2107}
2108
2109const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2110 return fGpu->getQuadIndexBuffer();
2111}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002112
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002113void GrContext::convolveInX(GrTexture* texture,
2114 const SkRect& rect,
2115 const float* kernel,
2116 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002117 ASSERT_OWNED_RESOURCE(texture);
2118
bsalomon@google.com99621082011-11-15 16:47:16 +00002119 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002120 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2121}
2122
2123void GrContext::convolveInY(GrTexture* texture,
2124 const SkRect& rect,
2125 const float* kernel,
2126 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002127 ASSERT_OWNED_RESOURCE(texture);
2128
bsalomon@google.com99621082011-11-15 16:47:16 +00002129 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002130 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2131}
2132
2133void GrContext::convolve(GrTexture* texture,
2134 const SkRect& rect,
2135 float imageIncrement[2],
2136 const float* kernel,
2137 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002138 ASSERT_OWNED_RESOURCE(texture);
2139
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002140 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002141 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002142 GrMatrix sampleM;
2143 sampleM.setIDiv(texture->width(), texture->height());
2144 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2145 GrSamplerState::kConvolution_Filter,
2146 sampleM);
2147 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2148 kernel,
2149 imageIncrement);
2150
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002151 drawState->setViewMatrix(GrMatrix::I());
2152 drawState->setTexture(0, texture);
2153 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002154 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002155 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2156}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002157
2158///////////////////////////////////////////////////////////////////////////////