blob: a4066299eddef04acea6a291ced02d91549374f9 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.com1fadb202011-12-12 16:10:08 +000010#include "GrContext.h"
11
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000014#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015#include "GrIndexBuffer.h"
16#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000017#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000018#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000020#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000021#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000022#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000023#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024
bsalomon@google.com91958362011-06-13 17:58:13 +000025// Using MSAA seems to be slower for some yet unknown reason.
26#define PREFER_MSAA_OFFSCREEN_AA 0
27#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000028
bsalomon@google.com27847de2011-02-22 20:59:41 +000029#define DEFER_TEXT_RENDERING 1
30
31#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
32
bsalomon@google.comd46e2422011-09-23 17:40:07 +000033// When we're using coverage AA but the blend is incompatible (given gpu
34// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000035#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000036
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000037static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000039
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
bsalomon@google.combc4b6542011-11-19 13:56:11 +000048#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
49
bsalomon@google.com05ef5102011-05-02 21:14:59 +000050GrContext* GrContext::Create(GrEngine engine,
51 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000052 GrContext* ctx = NULL;
53 GrGpu* fGpu = GrGpu::Create(engine, context3D);
54 if (NULL != fGpu) {
55 ctx = new GrContext(fGpu);
56 fGpu->unref();
57 }
58 return ctx;
59}
60
bsalomon@google.com27847de2011-02-22 20:59:41 +000061GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000068
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000072 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000073}
74
bsalomon@google.com8fe72472011-03-30 21:26:44 +000075void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000076 contextDestroyed();
77 this->setupDrawBuffer();
78}
79
80void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 // abandon first to so destructors
82 // don't try to free the resources in the API.
83 fGpu->abandonResources();
84
bsalomon@google.com30085192011-08-19 15:42:31 +000085 // a path renderer may be holding onto resources that
86 // are now unusable
87 GrSafeSetNull(fPathRendererChain);
88
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBuffer;
90 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferVBAllocPool;
93 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000094
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 delete fDrawBufferIBAllocPool;
96 fDrawBufferIBAllocPool = NULL;
97
bsalomon@google.com205d4602011-04-25 12:43:45 +000098 GrSafeSetNull(fAAFillRectIndexBuffer);
99 GrSafeSetNull(fAAStrokeRectIndexBuffer);
100
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101 fTextureCache->removeAll();
102 fFontCache->freeAll();
103 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000104}
105
106void GrContext::resetContext() {
107 fGpu->markContextDirty();
108}
109
110void GrContext::freeGpuResources() {
111 this->flush();
112 fTextureCache->removeAll();
113 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000114 // a path renderer may be holding onto resources
115 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000116}
117
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000118////////////////////////////////////////////////////////////////////////////////
119
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000120int GrContext::PaintStageVertexLayoutBits(
121 const GrPaint& paint,
122 const bool hasTexCoords[GrPaint::kTotalStages]) {
123 int stageMask = paint.getActiveStageMask();
124 int layout = 0;
125 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
126 if ((1 << i) & stageMask) {
127 if (NULL != hasTexCoords && hasTexCoords[i]) {
128 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
129 } else {
130 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
131 }
132 }
133 }
134 return layout;
135}
136
137
138////////////////////////////////////////////////////////////////////////////////
139
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000140enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000141 // flags for textures
142 kNPOTBit = 0x1,
143 kFilterBit = 0x2,
144 kScratchBit = 0x4,
145
146 // resource type
147 kTextureBit = 0x8,
148 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000149};
150
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000151GrTexture* GrContext::TextureCacheEntry::texture() const {
152 if (NULL == fEntry) {
153 return NULL;
154 } else {
155 return (GrTexture*) fEntry->resource();
156 }
157}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000158
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000159namespace {
160// returns true if this is a "special" texture because of gpu NPOT limitations
161bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000162 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163 GrContext::TextureKey clientKey,
164 int width,
165 int height,
166 bool scratch,
167 uint32_t v[4]) {
168 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
169 // we assume we only need 16 bits of width and height
170 // assert that texture creation will fail anyway if this assumption
171 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000172 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000173 v[0] = clientKey & 0xffffffffUL;
174 v[1] = (clientKey >> 32) & 0xffffffffUL;
175 v[2] = width | (height << 16);
176
177 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000178 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
180
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000181 bool tiled = NULL != sampler &&
182 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
183 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184
185 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000187 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 }
190 }
191 }
192
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 if (scratch) {
194 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197 v[3] |= kTextureBit;
198
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199 return v[3] & kNPOTBit;
200}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000201
202// we should never have more than one stencil buffer with same combo of
203// (width,height,samplecount)
204void gen_stencil_key_values(int width, int height,
205 int sampleCnt, uint32_t v[4]) {
206 v[0] = width;
207 v[1] = height;
208 v[2] = sampleCnt;
209 v[3] = kStencilBufferBit;
210}
211
212void gen_stencil_key_values(const GrStencilBuffer* sb,
213 uint32_t v[4]) {
214 gen_stencil_key_values(sb->width(), sb->height(),
215 sb->numSamples(), v);
216}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000217
218// This should be subsumed by a future version of GrDrawState
219// It does not reset stage textures/samplers or per-vertex-edge-aa state since
220// they aren't used unless the vertex layout references them.
221// It also doesn't set the render target.
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000222void reset_draw_state(GrDrawState* drawState){
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000223
224 drawState->setViewMatrix(GrMatrix::I());
225 drawState->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000226 drawState->resetStateFlags();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000227 drawState->setEdgeAAData(NULL, 0);
228 drawState->disableStencil();
229 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000230 drawState->setBlendFunc(kOne_BlendCoeff,
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000231 kZero_BlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000232 drawState->setFirstCoverageStage(GrDrawState::kNumStages);
233 drawState->setDrawFace(GrDrawState::kBoth_DrawFace);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000234}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000235}
236
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000237GrContext::TextureCacheEntry GrContext::findAndLockTexture(
238 TextureKey key,
239 int width,
240 int height,
241 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000242 uint32_t v[4];
243 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
244 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000245 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
246 GrResourceCache::kNested_LockType));
247}
248
bsalomon@google.comfb309512011-11-30 14:13:48 +0000249bool GrContext::isTextureInCache(TextureKey key,
250 int width,
251 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000252 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000253 uint32_t v[4];
254 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
255 GrResourceKey resourceKey(v);
256 return fTextureCache->hasKey(resourceKey);
257}
258
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000259GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000260 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000261 uint32_t v[4];
262 gen_stencil_key_values(sb, v);
263 GrResourceKey resourceKey(v);
264 return fTextureCache->createAndLock(resourceKey, sb);
265}
266
267GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
268 int sampleCnt) {
269 uint32_t v[4];
270 gen_stencil_key_values(width, height, sampleCnt, v);
271 GrResourceKey resourceKey(v);
272 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
273 GrResourceCache::kSingle_LockType);
274 if (NULL != entry) {
275 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
276 return sb;
277 } else {
278 return NULL;
279 }
280}
281
282void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000283 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000284 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000285}
286
287static void stretchImage(void* dst,
288 int dstW,
289 int dstH,
290 void* src,
291 int srcW,
292 int srcH,
293 int bpp) {
294 GrFixed dx = (srcW << 16) / dstW;
295 GrFixed dy = (srcH << 16) / dstH;
296
297 GrFixed y = dy >> 1;
298
299 int dstXLimit = dstW*bpp;
300 for (int j = 0; j < dstH; ++j) {
301 GrFixed x = dx >> 1;
302 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
303 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
304 for (int i = 0; i < dstXLimit; i += bpp) {
305 memcpy((uint8_t*) dstRow + i,
306 (uint8_t*) srcRow + (x>>16)*bpp,
307 bpp);
308 x += dx;
309 }
310 y += dy;
311 }
312}
313
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000314GrContext::TextureCacheEntry GrContext::createAndLockTexture(
315 TextureKey key,
316 const GrSamplerState* sampler,
317 const GrTextureDesc& desc,
318 void* srcData,
319 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000320 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000321
322#if GR_DUMP_TEXTURE_UPLOAD
323 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
324#endif
325
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000326 TextureCacheEntry entry;
327 uint32_t v[4];
328 bool special = gen_texture_key_values(fGpu, sampler, key,
329 desc.fWidth, desc.fHeight, false, v);
330 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000331
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000332 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000333 GrAssert(NULL != sampler);
334 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
335 desc.fWidth,
336 desc.fHeight,
337 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000338
339 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000340 clampEntry = this->createAndLockTexture(key, NULL, desc,
341 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000342 GrAssert(NULL != clampEntry.texture());
343 if (NULL == clampEntry.texture()) {
344 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000345 }
346 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000347 GrTextureDesc rtDesc = desc;
348 rtDesc.fFlags = rtDesc.fFlags |
349 kRenderTarget_GrTextureFlagBit |
350 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000351 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
352 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000353
354 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
355
356 if (NULL != texture) {
357 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000358 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000359 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000360 drawState->setRenderTarget(texture->asRenderTarget());
361 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000362
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000363 GrSamplerState::Filter filter;
364 // if filtering is not desired then we want to ensure all
365 // texels in the resampled image are copies of texels from
366 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000367 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000368 filter = GrSamplerState::kNearest_Filter;
369 } else {
370 filter = GrSamplerState::kBilinear_Filter;
371 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000372 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
373 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000374
375 static const GrVertexLayout layout =
376 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
377 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
378
379 if (arg.succeeded()) {
380 GrPoint* verts = (GrPoint*) arg.vertices();
381 verts[0].setIRectFan(0, 0,
382 texture->width(),
383 texture->height(),
384 2*sizeof(GrPoint));
385 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
386 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
387 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000388 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000390 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 } else {
392 // TODO: Our CPU stretch doesn't filter. But we create separate
393 // stretched textures when the sampler state is either filtered or
394 // not. Either implement filtered stretch blit on CPU or just create
395 // one when FBO case fails.
396
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000397 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 // no longer need to clamp at min RT size.
399 rtDesc.fWidth = GrNextPow2(desc.fWidth);
400 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000401 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000402 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000403 rtDesc.fWidth *
404 rtDesc.fHeight);
405 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
406 srcData, desc.fWidth, desc.fHeight, bpp);
407
408 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
409
410 GrTexture* texture = fGpu->createTexture(rtDesc,
411 stretchedPixels.get(),
412 stretchedRowBytes);
413 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000417
418 } else {
419 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
420 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000422 }
423 }
424 return entry;
425}
426
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427namespace {
428inline void gen_scratch_tex_key_values(const GrGpu* gpu,
429 const GrTextureDesc& desc,
430 uint32_t v[4]) {
431 // Instead of a client-provided key of the texture contents
432 // we create a key of from the descriptor.
433 GrContext::TextureKey descKey = desc.fAALevel |
434 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000435 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000436 // this code path isn't friendly to tiling with NPOT restricitons
437 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000438 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
439 desc.fHeight, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000440}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000441}
442
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000443GrContext::TextureCacheEntry GrContext::lockScratchTexture(
444 const GrTextureDesc& inDesc,
445 ScratchTexMatch match) {
446
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000447 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000448 if (kExact_ScratchTexMatch != match) {
449 // bin by pow2 with a reasonable min
450 static const int MIN_SIZE = 256;
451 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
452 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
453 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000454
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000455 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000456 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
457
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000458 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000459 int origWidth = desc.fWidth;
460 int origHeight = desc.fHeight;
461 bool doubledW = false;
462 bool doubledH = false;
463
464 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000465 uint32_t v[4];
466 gen_scratch_tex_key_values(fGpu, desc, v);
467 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000468 entry = fTextureCache->findAndLock(key,
469 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000470 // if we miss, relax the fit of the flags...
471 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000472 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000473 break;
474 }
475 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
476 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
477 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
478 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
479 } else if (!doubledW) {
480 desc.fFlags = inDesc.fFlags;
481 desc.fWidth *= 2;
482 doubledW = true;
483 } else if (!doubledH) {
484 desc.fFlags = inDesc.fFlags;
485 desc.fWidth = origWidth;
486 desc.fHeight *= 2;
487 doubledH = true;
488 } else {
489 break;
490 }
491
492 } while (true);
493
494 if (NULL == entry) {
495 desc.fFlags = inDesc.fFlags;
496 desc.fWidth = origWidth;
497 desc.fHeight = origHeight;
498 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
499 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000500 uint32_t v[4];
501 gen_scratch_tex_key_values(fGpu, desc, v);
502 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000503 entry = fTextureCache->createAndLock(key, texture);
504 }
505 }
506
507 // If the caller gives us the same desc/sampler twice we don't want
508 // to return the same texture the second time (unless it was previously
509 // released). So we detach the entry from the cache and reattach at release.
510 if (NULL != entry) {
511 fTextureCache->detach(entry);
512 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000514}
515
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000516void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000517 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518 // If this is a scratch texture we detached it from the cache
519 // while it was locked (to avoid two callers simultaneously getting
520 // the same texture).
521 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
522 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000523 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000524 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000525 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000526}
527
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000528GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000529 void* srcData,
530 size_t rowBytes) {
531 return fGpu->createTexture(desc, srcData, rowBytes);
532}
533
534void GrContext::getTextureCacheLimits(int* maxTextures,
535 size_t* maxTextureBytes) const {
536 fTextureCache->getLimits(maxTextures, maxTextureBytes);
537}
538
539void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
540 fTextureCache->setLimits(maxTextures, maxTextureBytes);
541}
542
bsalomon@google.com91958362011-06-13 17:58:13 +0000543int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000544 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000545}
546
547int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000548 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000549}
550
551///////////////////////////////////////////////////////////////////////////////
552
bsalomon@google.come269f212011-11-07 13:29:52 +0000553GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
554 return fGpu->createPlatformTexture(desc);
555}
556
557GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
558 return fGpu->createPlatformRenderTarget(desc);
559}
560
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000561GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
562 // validate flags here so that GrGpu subclasses don't have to check
563 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
564 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000565 return NULL;
566 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000567 if (desc.fSampleCnt &&
568 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000569 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000570 }
571 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
572 desc.fSampleCnt &&
573 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
574 return NULL;
575 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000576 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577}
578
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000579///////////////////////////////////////////////////////////////////////////////
580
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000581bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000582 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000583 const GrDrawTarget::Caps& caps = fGpu->getCaps();
584 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000585 return false;
586 }
587
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
589
590 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000591 bool tiled = NULL != sampler &&
592 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
593 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000594 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000595 return false;
596 }
597 }
598 return true;
599}
600
601////////////////////////////////////////////////////////////////////////////////
602
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000603const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
604
bsalomon@google.com27847de2011-02-22 20:59:41 +0000605void GrContext::setClip(const GrClip& clip) {
606 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000607 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000608}
609
610void GrContext::setClip(const GrIRect& rect) {
611 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000612 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000613 fGpu->setClip(clip);
614}
615
616////////////////////////////////////////////////////////////////////////////////
617
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000618void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000619 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000620 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000621}
622
623void GrContext::drawPaint(const GrPaint& paint) {
624 // set rect to be big enough to fill the space, but not super-huge, so we
625 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000626 GrRect r;
627 r.setLTRB(0, 0,
628 GrIntToScalar(getRenderTarget()->width()),
629 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000630 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000631 SkTLazy<GrPaint> tmpPaint;
632 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000633 GrDrawState* drawState = fGpu->drawState();
634 GrAutoMatrix am;
635
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000636 // We attempt to map r by the inverse matrix and draw that. mapRect will
637 // map the four corners and bound them with a new rect. This will not
638 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000639 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000640 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000641 GrPrintf("Could not invert matrix");
642 return;
643 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000644 inverse.mapRect(&r);
645 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000646 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000647 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000648 GrPrintf("Could not invert matrix");
649 return;
650 }
651 tmpPaint.set(paint);
652 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
653 p = tmpPaint.get();
654 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000655 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000657 // by definition this fills the entire clip, no need for AA
658 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000659 if (!tmpPaint.isValid()) {
660 tmpPaint.set(paint);
661 p = tmpPaint.get();
662 }
663 GrAssert(p == tmpPaint.get());
664 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000665 }
666 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000667}
668
bsalomon@google.com205d4602011-04-25 12:43:45 +0000669////////////////////////////////////////////////////////////////////////////////
670
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000671namespace {
672inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
673 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
674}
675}
676
bsalomon@google.com91958362011-06-13 17:58:13 +0000677struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000678 enum Downsample {
679 k4x4TwoPass_Downsample,
680 k4x4SinglePass_Downsample,
681 kFSAA_Downsample
682 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000683 int fTileSizeX;
684 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000685 int fTileCountX;
686 int fTileCountY;
687 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000688 GrAutoScratchTexture fOffscreen0;
689 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000690 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000691 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000692};
693
bsalomon@google.com471d4712011-08-23 15:45:25 +0000694bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000695 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000696#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000697 return false;
698#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000699 // Line primitves are always rasterized as 1 pixel wide.
700 // Super-sampling would make them too thin but MSAA would be OK.
701 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000702 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000703 return false;
704 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000705 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000706 return false;
707 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000708 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000709#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000710 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000711#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000712 return false;
713 }
714 return true;
715#endif
716}
717
bsalomon@google.com91958362011-06-13 17:58:13 +0000718bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000719 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000720 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000721 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000722 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000723
724 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000725
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000726 GrAssert(NULL == record->fOffscreen0.texture());
727 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000728 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000730 int boundW = boundRect.width();
731 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000732
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000733 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000734
735 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
736 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
737
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000738 if (requireStencil) {
739 desc.fFlags = kRenderTarget_GrTextureFlagBit;
740 } else {
741 desc.fFlags = kRenderTarget_GrTextureFlagBit |
742 kNoStencil_GrTextureFlagBit;
743 }
744
bsalomon@google.comc4364992011-11-07 15:54:49 +0000745 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000746
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000747 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000748 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000749 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000750 desc.fAALevel = kMed_GrAALevel;
751 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000752 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000753 OffscreenRecord::k4x4SinglePass_Downsample :
754 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000755 record->fScale = OFFSCREEN_SSAA_SCALE;
756 // both downsample paths assume this
757 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000758 desc.fAALevel = kNone_GrAALevel;
759 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000760
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000761 desc.fWidth *= record->fScale;
762 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000763 record->fOffscreen0.set(this, desc);
764 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000765 return false;
766 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000767 // the approximate lookup might have given us some slop space, might as well
768 // use it when computing the tiles size.
769 // these are scale values, will adjust after considering
770 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000771 record->fTileSizeX = record->fOffscreen0.texture()->width();
772 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000773
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000774 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000775 desc.fWidth /= 2;
776 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000777 record->fOffscreen1.set(this, desc);
778 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000779 return false;
780 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000781 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000782 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000783 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000784 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000785 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000786 record->fTileSizeX /= record->fScale;
787 record->fTileSizeY /= record->fScale;
788
789 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
790 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
791
tomhudson@google.com237a4612011-07-19 15:44:00 +0000792 record->fClip = target->getClip();
793
bsalomon@google.com91958362011-06-13 17:58:13 +0000794 target->saveCurrentDrawState(&record->fSavedState);
795 return true;
796}
797
798void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
799 const GrIRect& boundRect,
800 int tileX, int tileY,
801 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000802
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000803 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000804 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000805
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000806 GrPaint tempPaint;
807 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000808 this->setPaint(tempPaint, target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000809 GrDrawState* drawState = target->drawState();
810 drawState->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000811#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000812 target->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000813#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000814
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000815 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000816 int left = boundRect.fLeft + tileX * record->fTileSizeX;
817 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000818 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000819 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000820 GrMatrix scaleM;
821 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000822 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000823
bsalomon@google.com91958362011-06-13 17:58:13 +0000824 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000825 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000826 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000827 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000828 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
829 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000830 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000831#if 0
832 // visualize tile boundaries by setting edges of offscreen to white
833 // and interior to tranparent. black.
834 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000835
bsalomon@google.com91958362011-06-13 17:58:13 +0000836 static const int gOffset = 2;
837 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
838 record->fScale * w - gOffset,
839 record->fScale * h - gOffset);
840 target->clear(&clear2, 0x0);
841#else
842 target->clear(&clear, 0x0);
843#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000844}
845
bsalomon@google.com91958362011-06-13 17:58:13 +0000846void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000847 const GrPaint& paint,
848 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000849 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000850 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000851 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000852 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000853 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000854 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000855 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
856 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000857 tileRect.fRight = (tileX == record->fTileCountX-1) ?
858 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000859 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000860 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
861 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000862 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000863
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000864 GrSamplerState::Filter filter;
865 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
866 filter = GrSamplerState::k4x4Downsample_Filter;
867 } else {
868 filter = GrSamplerState::kBilinear_Filter;
869 }
870
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000871 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 int scale;
873
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000874 enum {
875 kOffscreenStage = GrPaint::kTotalStages,
876 };
877
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000878 GrDrawState* drawState = target->drawState();
879
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000880 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000881 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000882 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000883 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000884
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000885 // Do 2x2 downsample from first to second
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000886 drawState->setTexture(kOffscreenStage, src);
887 drawState->setRenderTarget(dst);
888 drawState->setViewMatrix(GrMatrix::I());
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000889 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
890 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000891 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
892 scale * GR_Scalar1 / src->height());
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000893 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
894 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000895 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
896
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000897 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000898 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000899 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000900 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000901 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000902 } else {
903 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
904 record->fDownsample);
905 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000906 }
907
bsalomon@google.com91958362011-06-13 17:58:13 +0000908 // setup for draw back to main RT, we use the original
909 // draw state setup by the caller plus an additional coverage
910 // stage to handle the AA resolve. Also, we use an identity
911 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000912 int stageMask = paint.getActiveStageMask();
913
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000914 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000915 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000916
917 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000918 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000919 if (drawState->getViewInverse(&invVM)) {
920 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000921 }
922 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000923 // This is important when tiling, otherwise second tile's
924 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000925 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000926
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000927 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000928 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
929 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000930 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
931 scale * GR_Scalar1 / src->height());
932 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
933 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000934
reed@google.com20efde72011-05-09 17:00:02 +0000935 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000936 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000937 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000938 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000939}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000940
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000941void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
942 GrPathRenderer* pr,
943 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000944 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000945}
946
947////////////////////////////////////////////////////////////////////////////////
948
bsalomon@google.com27847de2011-02-22 20:59:41 +0000949/* create a triangle strip that strokes the specified triangle. There are 8
950 unique vertices, but we repreat the last 2 to close up. Alternatively we
951 could use an indices array, and then only send 8 verts, but not sure that
952 would be faster.
953 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000954static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000955 GrScalar width) {
956 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000957 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000958
959 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
960 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
961 verts[2].set(rect.fRight - rad, rect.fTop + rad);
962 verts[3].set(rect.fRight + rad, rect.fTop - rad);
963 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
964 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
965 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
966 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
967 verts[8] = verts[0];
968 verts[9] = verts[1];
969}
970
bsalomon@google.com205d4602011-04-25 12:43:45 +0000971static void setInsetFan(GrPoint* pts, size_t stride,
972 const GrRect& r, GrScalar dx, GrScalar dy) {
973 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
974}
975
976static const uint16_t gFillAARectIdx[] = {
977 0, 1, 5, 5, 4, 0,
978 1, 2, 6, 6, 5, 1,
979 2, 3, 7, 7, 6, 2,
980 3, 0, 4, 4, 7, 3,
981 4, 5, 6, 6, 7, 4,
982};
983
984int GrContext::aaFillRectIndexCount() const {
985 return GR_ARRAY_COUNT(gFillAARectIdx);
986}
987
988GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
989 if (NULL == fAAFillRectIndexBuffer) {
990 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
991 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000992 if (NULL != fAAFillRectIndexBuffer) {
993 #if GR_DEBUG
994 bool updated =
995 #endif
996 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
997 sizeof(gFillAARectIdx));
998 GR_DEBUGASSERT(updated);
999 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001000 }
1001 return fAAFillRectIndexBuffer;
1002}
1003
1004static const uint16_t gStrokeAARectIdx[] = {
1005 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
1006 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1007 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1008 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1009
1010 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1011 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1012 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1013 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1014
1015 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1016 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1017 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1018 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1019};
1020
1021int GrContext::aaStrokeRectIndexCount() const {
1022 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1023}
1024
1025GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1026 if (NULL == fAAStrokeRectIndexBuffer) {
1027 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1028 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001029 if (NULL != fAAStrokeRectIndexBuffer) {
1030 #if GR_DEBUG
1031 bool updated =
1032 #endif
1033 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1034 sizeof(gStrokeAARectIdx));
1035 GR_DEBUGASSERT(updated);
1036 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001037 }
1038 return fAAStrokeRectIndexBuffer;
1039}
1040
bsalomon@google.coma3108262011-10-10 14:08:47 +00001041static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1042 bool useCoverage) {
1043 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001044 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001045 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001046 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1047 }
1048 }
1049 if (useCoverage) {
1050 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1051 } else {
1052 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1053 }
1054 return layout;
1055}
1056
bsalomon@google.com205d4602011-04-25 12:43:45 +00001057void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 const GrRect& devRect,
1059 bool useVertexCoverage) {
1060 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001061
1062 size_t vsize = GrDrawTarget::VertexSize(layout);
1063
1064 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001065 if (!geo.succeeded()) {
1066 GrPrintf("Failed to get space for vertices!\n");
1067 return;
1068 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001069 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1070 if (NULL == indexBuffer) {
1071 GrPrintf("Failed to create index buffer!\n");
1072 return;
1073 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001074
1075 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1076
1077 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1078 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1079
1080 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1081 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1082
1083 verts += sizeof(GrPoint);
1084 for (int i = 0; i < 4; ++i) {
1085 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1086 }
1087
bsalomon@google.coma3108262011-10-10 14:08:47 +00001088 GrColor innerColor;
1089 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001090 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001091 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001092 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001093 }
1094
bsalomon@google.com205d4602011-04-25 12:43:45 +00001095 verts += 4 * vsize;
1096 for (int i = 0; i < 4; ++i) {
1097 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1098 }
1099
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001100 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001101
1102 target->drawIndexed(kTriangles_PrimitiveType, 0,
1103 0, 8, this->aaFillRectIndexCount());
1104}
1105
bsalomon@google.coma3108262011-10-10 14:08:47 +00001106void GrContext::strokeAARect(GrDrawTarget* target,
1107 const GrRect& devRect,
1108 const GrVec& devStrokeSize,
1109 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001110 const GrScalar& dx = devStrokeSize.fX;
1111 const GrScalar& dy = devStrokeSize.fY;
1112 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1113 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1114
bsalomon@google.com205d4602011-04-25 12:43:45 +00001115 GrScalar spare;
1116 {
1117 GrScalar w = devRect.width() - dx;
1118 GrScalar h = devRect.height() - dy;
1119 spare = GrMin(w, h);
1120 }
1121
1122 if (spare <= 0) {
1123 GrRect r(devRect);
1124 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001125 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001126 return;
1127 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001128 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001129 size_t vsize = GrDrawTarget::VertexSize(layout);
1130
1131 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001132 if (!geo.succeeded()) {
1133 GrPrintf("Failed to get space for vertices!\n");
1134 return;
1135 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001136 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1137 if (NULL == indexBuffer) {
1138 GrPrintf("Failed to create index buffer!\n");
1139 return;
1140 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001141
1142 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1143
1144 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1145 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1146 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1147 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1148
1149 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1150 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1151 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1152 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1153
1154 verts += sizeof(GrPoint);
1155 for (int i = 0; i < 4; ++i) {
1156 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1157 }
1158
bsalomon@google.coma3108262011-10-10 14:08:47 +00001159 GrColor innerColor;
1160 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001161 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001162 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001163 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001164 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001165 verts += 4 * vsize;
1166 for (int i = 0; i < 8; ++i) {
1167 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1168 }
1169
1170 verts += 8 * vsize;
1171 for (int i = 0; i < 8; ++i) {
1172 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1173 }
1174
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001175 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001176 target->drawIndexed(kTriangles_PrimitiveType,
1177 0, 0, 16, aaStrokeRectIndexCount());
1178}
1179
reed@google.com20efde72011-05-09 17:00:02 +00001180/**
1181 * Returns true if the rects edges are integer-aligned.
1182 */
1183static bool isIRect(const GrRect& r) {
1184 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1185 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1186}
1187
bsalomon@google.com205d4602011-04-25 12:43:45 +00001188static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001189 const GrRect& rect,
1190 GrScalar width,
1191 const GrMatrix* matrix,
1192 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001193 GrRect* devRect,
1194 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001195 // we use a simple alpha ramp to do aa on axis-aligned rects
1196 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001197 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001198
bsalomon@google.coma3108262011-10-10 14:08:47 +00001199 // we are keeping around the "tweak the alpha" trick because
1200 // it is our only hope for the fixed-pipe implementation.
1201 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001202 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001203 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001204 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001205 if (target->getCaps().fSupportPerVertexCoverage) {
1206 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001207#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001208 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001209#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001210 return false;
1211 } else {
1212 *useVertexCoverage = true;
1213 }
1214 } else {
1215 GrPrintf("Rect AA dropped because no support for coverage.\n");
1216 return false;
1217 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001218 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001219 const GrDrawState& drawState = target->getDrawState();
1220 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001221 return false;
1222 }
1223
bsalomon@google.com471d4712011-08-23 15:45:25 +00001224 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001225 return false;
1226 }
1227
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001228 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001229 return false;
1230 }
1231
1232 if (NULL != matrix &&
1233 !matrix->preservesAxisAlignment()) {
1234 return false;
1235 }
1236
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001237 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001238 if (NULL != matrix) {
1239 combinedMatrix->preConcat(*matrix);
1240 GrAssert(combinedMatrix->preservesAxisAlignment());
1241 }
1242
1243 combinedMatrix->mapRect(devRect, rect);
1244 devRect->sort();
1245
1246 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001247 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001248 } else {
1249 return true;
1250 }
1251}
1252
bsalomon@google.com27847de2011-02-22 20:59:41 +00001253void GrContext::drawRect(const GrPaint& paint,
1254 const GrRect& rect,
1255 GrScalar width,
1256 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001257 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258
1259 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001260 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001261
bsalomon@google.com205d4602011-04-25 12:43:45 +00001262 GrRect devRect = rect;
1263 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001264 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001265 bool needAA = paint.fAntiAlias &&
1266 !this->getRenderTarget()->isMultisampled();
1267 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1268 &combinedMatrix, &devRect,
1269 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001270
1271 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001272 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001273 if (width >= 0) {
1274 GrVec strokeSize;;
1275 if (width > 0) {
1276 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001277 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001278 strokeSize.setAbs(strokeSize);
1279 } else {
1280 strokeSize.set(GR_Scalar1, GR_Scalar1);
1281 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001282 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001283 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001284 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001285 }
1286 return;
1287 }
1288
bsalomon@google.com27847de2011-02-22 20:59:41 +00001289 if (width >= 0) {
1290 // TODO: consider making static vertex buffers for these cases.
1291 // Hairline could be done by just adding closing vertex to
1292 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001293 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1294
bsalomon@google.com27847de2011-02-22 20:59:41 +00001295 static const int worstCaseVertCount = 10;
1296 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1297
1298 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001299 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300 return;
1301 }
1302
1303 GrPrimitiveType primType;
1304 int vertCount;
1305 GrPoint* vertex = geo.positions();
1306
1307 if (width > 0) {
1308 vertCount = 10;
1309 primType = kTriangleStrip_PrimitiveType;
1310 setStrokeRectStrip(vertex, rect, width);
1311 } else {
1312 // hairline
1313 vertCount = 5;
1314 primType = kLineStrip_PrimitiveType;
1315 vertex[0].set(rect.fLeft, rect.fTop);
1316 vertex[1].set(rect.fRight, rect.fTop);
1317 vertex[2].set(rect.fRight, rect.fBottom);
1318 vertex[3].set(rect.fLeft, rect.fBottom);
1319 vertex[4].set(rect.fLeft, rect.fTop);
1320 }
1321
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001322 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001323 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001324 GrDrawState* drawState = target->drawState();
1325 avmr.set(drawState);
1326 drawState->preConcatViewMatrix(*matrix);
1327 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001328 }
1329
1330 target->drawNonIndexed(primType, 0, vertCount);
1331 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001332#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001333 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001334 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1335 if (NULL == sqVB) {
1336 GrPrintf("Failed to create static rect vb.\n");
1337 return;
1338 }
1339 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001340 GrDrawState* drawState = target->drawState();
1341 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001342 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001343 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001344 0, rect.height(), rect.fTop,
1345 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001346
1347 if (NULL != matrix) {
1348 m.postConcat(*matrix);
1349 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001350 drawState->preConcatViewMatrix(m);
1351 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001352
bsalomon@google.com27847de2011-02-22 20:59:41 +00001353 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001354#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001355 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001356#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001357 }
1358}
1359
1360void GrContext::drawRectToRect(const GrPaint& paint,
1361 const GrRect& dstRect,
1362 const GrRect& srcRect,
1363 const GrMatrix* dstMatrix,
1364 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001365 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001366
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001367 // srcRect refers to paint's first texture
1368 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001369 drawRect(paint, dstRect, -1, dstMatrix);
1370 return;
1371 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001372
bsalomon@google.com27847de2011-02-22 20:59:41 +00001373 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1374
1375#if GR_STATIC_RECT_VB
1376 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001377 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001378 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001379 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001380
1381 GrMatrix m;
1382
1383 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1384 0, dstRect.height(), dstRect.fTop,
1385 0, 0, GrMatrix::I()[8]);
1386 if (NULL != dstMatrix) {
1387 m.postConcat(*dstMatrix);
1388 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001389 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001390
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001391 // srcRect refers to first stage
1392 int otherStageMask = paint.getActiveStageMask() &
1393 (~(1 << GrPaint::kFirstTextureStage));
1394 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001395 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001396 }
1397
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1399 0, srcRect.height(), srcRect.fTop,
1400 0, 0, GrMatrix::I()[8]);
1401 if (NULL != srcMatrix) {
1402 m.postConcat(*srcMatrix);
1403 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001404 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001406 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1407 if (NULL == sqVB) {
1408 GrPrintf("Failed to create static rect vb.\n");
1409 return;
1410 }
1411 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001412 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1413#else
1414
1415 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001416#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001418#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001419 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1420#endif
1421
tomhudson@google.com93813632011-10-27 20:21:16 +00001422 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1423 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001424 srcRects[0] = &srcRect;
1425 srcMatrices[0] = srcMatrix;
1426
1427 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1428#endif
1429}
1430
1431void GrContext::drawVertices(const GrPaint& paint,
1432 GrPrimitiveType primitiveType,
1433 int vertexCount,
1434 const GrPoint positions[],
1435 const GrPoint texCoords[],
1436 const GrColor colors[],
1437 const uint16_t indices[],
1438 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001439 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001440
1441 GrDrawTarget::AutoReleaseGeometry geo;
1442
1443 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1444
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001445 bool hasTexCoords[GrPaint::kTotalStages] = {
1446 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1447 0 // remaining stages use positions
1448 };
1449
1450 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001451
1452 if (NULL != colors) {
1453 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001454 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001455 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001456
1457 if (sizeof(GrPoint) != vertexSize) {
1458 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001459 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460 return;
1461 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001462 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001464 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1465 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001466 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001467 NULL,
1468 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469 void* curVertex = geo.vertices();
1470
1471 for (int i = 0; i < vertexCount; ++i) {
1472 *((GrPoint*)curVertex) = positions[i];
1473
1474 if (texOffsets[0] > 0) {
1475 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1476 }
1477 if (colorOffset > 0) {
1478 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1479 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001480 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001481 }
1482 } else {
1483 target->setVertexSourceToArray(layout, positions, vertexCount);
1484 }
1485
bsalomon@google.com91958362011-06-13 17:58:13 +00001486 // we don't currently apply offscreen AA to this path. Need improved
1487 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001488
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001489 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001490 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001491 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001492 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001493 target->drawNonIndexed(primitiveType, 0, vertexCount);
1494 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001495}
1496
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001497///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498
reed@google.com07f3ee12011-05-16 17:21:57 +00001499void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1500 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001501
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001502 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001503 if (GrIsFillInverted(fill)) {
1504 this->drawPaint(paint);
1505 }
1506 return;
1507 }
1508
bsalomon@google.com27847de2011-02-22 20:59:41 +00001509 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001510
bsalomon@google.com289533a2011-10-27 12:34:25 +00001511 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1512
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001513 // An Assumption here is that path renderer would use some form of tweaking
1514 // the src color (either the input alpha or in the frag shader) to implement
1515 // aa. If we have some future driver-mojo path AA that can do the right
1516 // thing WRT to the blend then we'll need some query on the PR.
1517 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001518#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001519 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001520#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001521 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001522 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001523
1524 bool doOSAA = false;
1525 GrPathRenderer* pr = NULL;
1526 if (prAA) {
1527 pr = this->getPathRenderer(path, fill, true);
1528 if (NULL == pr) {
1529 prAA = false;
1530 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1531 pr = this->getPathRenderer(path, fill, false);
1532 }
1533 } else {
1534 pr = this->getPathRenderer(path, fill, false);
1535 }
1536
bsalomon@google.com30085192011-08-19 15:42:31 +00001537 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001538#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001539 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001540#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001541 return;
1542 }
1543
bsalomon@google.com289533a2011-10-27 12:34:25 +00001544 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001545 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001546
bsalomon@google.com289533a2011-10-27 12:34:25 +00001547 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001548 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001549 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001550 // compute bounds as intersection of rt size, clip, and path
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001551 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001552 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001553 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001554 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001555 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001556 return;
1557 }
1558 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001559 GrRect pathBounds = path.getBounds();
1560 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001561 if (NULL != translate) {
1562 pathBounds.offset(*translate);
1563 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001564 target->getDrawState().getViewMatrix().mapRect(&pathBounds,
1565 pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001566 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001567 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001568 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001569 return;
1570 }
1571 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001572 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001573 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1574 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001575 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1576 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1577 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001578 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001579 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1580 }
1581 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001582 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001583 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001584 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1585 GrRect rect;
1586 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001587 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1588 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001589 target->drawSimpleRect(rect, NULL, stageMask);
1590 }
1591 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001592 rect.iset(clipIBounds.fLeft, bound.fTop,
1593 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001594 target->drawSimpleRect(rect, NULL, stageMask);
1595 }
1596 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001597 rect.iset(bound.fRight, bound.fTop,
1598 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001599 target->drawSimpleRect(rect, NULL, stageMask);
1600 }
1601 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001602 rect.iset(clipIBounds.fLeft, bound.fBottom,
1603 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001604 target->drawSimpleRect(rect, NULL, stageMask);
1605 }
1606 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001607 return;
1608 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001609 }
1610 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001611}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001612
bsalomon@google.com27847de2011-02-22 20:59:41 +00001613////////////////////////////////////////////////////////////////////////////////
1614
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001615bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001616 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001617}
1618
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001619void GrContext::flush(int flagsBitfield) {
1620 if (kDiscard_FlushBit & flagsBitfield) {
1621 fDrawBuffer->reset();
1622 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001623 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001624 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001625 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001626 fGpu->forceRenderTargetFlush();
1627 }
1628}
1629
1630void GrContext::flushText() {
1631 if (kText_DrawCategory == fLastDrawCategory) {
1632 flushDrawBuffer();
1633 }
1634}
1635
1636void GrContext::flushDrawBuffer() {
1637#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001638 if (fDrawBuffer) {
1639 fDrawBuffer->playback(fGpu);
1640 fDrawBuffer->reset();
1641 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001642#endif
1643}
1644
bsalomon@google.com6f379512011-11-16 20:36:03 +00001645void GrContext::internalWriteTexturePixels(GrTexture* texture,
1646 int left, int top,
1647 int width, int height,
1648 GrPixelConfig config,
1649 const void* buffer,
1650 size_t rowBytes,
1651 uint32_t flags) {
1652 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001653 ASSERT_OWNED_RESOURCE(texture);
1654
bsalomon@google.com6f379512011-11-16 20:36:03 +00001655 if (!(kDontFlush_PixelOpsFlag & flags)) {
1656 this->flush();
1657 }
1658 // TODO: use scratch texture to perform conversion
1659 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1660 GrPixelConfigIsUnpremultiplied(config)) {
1661 return;
1662 }
1663
1664 fGpu->writeTexturePixels(texture, left, top, width, height,
1665 config, buffer, rowBytes);
1666}
1667
1668bool GrContext::internalReadTexturePixels(GrTexture* texture,
1669 int left, int top,
1670 int width, int height,
1671 GrPixelConfig config,
1672 void* buffer,
1673 size_t rowBytes,
1674 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001675 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001676 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001677
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001678 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001679 GrRenderTarget* target = texture->asRenderTarget();
1680 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001681 return this->internalReadRenderTargetPixels(target,
1682 left, top, width, height,
1683 config, buffer, rowBytes,
1684 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001685 } else {
1686 return false;
1687 }
1688}
1689
bsalomon@google.com6f379512011-11-16 20:36:03 +00001690bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1691 int left, int top,
1692 int width, int height,
1693 GrPixelConfig config,
1694 void* buffer,
1695 size_t rowBytes,
1696 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001697 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001698 ASSERT_OWNED_RESOURCE(target);
1699
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001700 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001701 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001702 if (NULL == target) {
1703 return false;
1704 }
1705 }
1706
1707 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1708 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1709 // not supported at this time.
1710 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1711 !GrPixelConfigIsUnpremultiplied(config)) {
1712 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001713 }
1714
bsalomon@google.com6f379512011-11-16 20:36:03 +00001715 if (!(kDontFlush_PixelOpsFlag & flags)) {
1716 this->flush();
1717 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001718
1719 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001720 bool swapRAndB = NULL != src &&
1721 fGpu->preferredReadPixelsConfig(config) ==
1722 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001723
1724 bool flipY = NULL != src &&
1725 fGpu->readPixelsWillPayForYFlip(target, left, top,
1726 width, height, config,
1727 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001728 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1729 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001730
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001731 if (NULL == src && alphaConversion) {
1732 // we should fallback to cpu conversion here. This could happen when
1733 // we were given an external render target by the client that is not
1734 // also a texture (e.g. FBO 0 in GL)
1735 return false;
1736 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001737 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001738 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001739 if (flipY || swapRAndB || alphaConversion) {
1740 GrAssert(NULL != src);
1741 if (swapRAndB) {
1742 config = GrPixelConfigSwapRAndB(config);
1743 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001744 }
1745 // Make the scratch a render target because we don't have a robust
1746 // readTexturePixels as of yet (it calls this function).
1747 const GrTextureDesc desc = {
1748 kRenderTarget_GrTextureFlagBit,
1749 kNone_GrAALevel,
1750 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001751 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001752 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001753
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001754 // When a full readback is faster than a partial we could always make
1755 // the scratch exactly match the passed rect. However, if we see many
1756 // different size rectangles we will trash our texture cache and pay the
1757 // cost of creating and destroying many textures. So, we only request
1758 // an exact match when the caller is reading an entire RT.
1759 ScratchTexMatch match = kApprox_ScratchTexMatch;
1760 if (0 == left &&
1761 0 == top &&
1762 target->width() == width &&
1763 target->height() == height &&
1764 fGpu->fullReadPixelsIsFasterThanPartial()) {
1765 match = kExact_ScratchTexMatch;
1766 }
1767 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001768 GrTexture* texture = ast.texture();
1769 if (!texture) {
1770 return false;
1771 }
1772 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001773 GrAssert(NULL != target);
1774
1775 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001776 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001777 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001778 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001779
bsalomon@google.comc4364992011-11-07 15:54:49 +00001780 GrMatrix matrix;
1781 if (flipY) {
1782 matrix.setTranslate(SK_Scalar1 * left,
1783 SK_Scalar1 * (top + height));
1784 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1785 } else {
1786 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1787 }
1788 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001789 drawState->sampler(0)->reset(matrix);
1790 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001791 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001792 GrRect rect;
1793 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1794 fGpu->drawSimpleRect(rect, NULL, 0x1);
1795 left = 0;
1796 top = 0;
1797 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001798 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001799 left, top, width, height,
1800 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001801}
1802
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001803void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1804 if (NULL == src || NULL == dst) {
1805 return;
1806 }
1807 ASSERT_OWNED_RESOURCE(src);
1808
1809 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001810 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001811 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001812 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001813 GrMatrix sampleM;
1814 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001815 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001816 drawState->sampler(0)->reset(sampleM);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001817 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1818 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1819}
1820
bsalomon@google.com6f379512011-11-16 20:36:03 +00001821void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1822 int left, int top,
1823 int width, int height,
1824 GrPixelConfig config,
1825 const void* buffer,
1826 size_t rowBytes,
1827 uint32_t flags) {
1828 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001829 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001830
1831 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001832 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001833 if (NULL == target) {
1834 return;
1835 }
1836 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001837
1838 // TODO: when underlying api has a direct way to do this we should use it
1839 // (e.g. glDrawPixels on desktop GL).
1840
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001841 // If the RT is also a texture and we don't have to do PM/UPM conversion
1842 // then take the texture path, which we expect to be at least as fast or
1843 // faster since it doesn't use an intermediate texture as we do below.
1844
1845#if !GR_MAC_BUILD
1846 // At least some drivers on the Mac get confused when glTexImage2D is called
1847 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1848 // determine what OS versions and/or HW is affected.
1849 if (NULL != target->asTexture() &&
1850 GrPixelConfigIsUnpremultiplied(target->config()) ==
1851 GrPixelConfigIsUnpremultiplied(config)) {
1852
1853 this->internalWriteTexturePixels(target->asTexture(),
1854 left, top, width, height,
1855 config, buffer, rowBytes, flags);
1856 return;
1857 }
1858#endif
1859
1860 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1861 GrPixelConfigSwapRAndB(config);
1862 if (swapRAndB) {
1863 config = GrPixelConfigSwapRAndB(config);
1864 }
1865
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001866 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001867 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001869 GrAutoScratchTexture ast(this, desc);
1870 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001871 if (NULL == texture) {
1872 return;
1873 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001874 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1875 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001876
bsalomon@google.com27847de2011-02-22 20:59:41 +00001877 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001878 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001879 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001880
1881 GrMatrix matrix;
1882 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001883 drawState->setViewMatrix(matrix);
1884 drawState->setRenderTarget(target);
1885 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001886
bsalomon@google.com5c638652011-07-18 19:31:59 +00001887 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001888 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1889 GrSamplerState::kNearest_Filter,
1890 matrix);
1891 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001892
1893 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1894 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001895 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001896 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1897 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001898 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001899 return;
1900 }
1901 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1902 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1903}
1904////////////////////////////////////////////////////////////////////////////////
1905
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001906void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001907 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001908
1909 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1910 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001911 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001912 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001913 if (paint.getTexture(i)) {
1914 *drawState->sampler(s) = paint.getTextureSampler(i);
1915 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001916 }
1917
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001918 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001919
1920 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1921 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001922 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001923 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001924 if (paint.getMask(i)) {
1925 *drawState->sampler(s) = paint.getMaskSampler(i);
1926 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001927 }
1928
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001929 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001930
1931 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001932 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001933 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001934 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001935 }
1936 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001937 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001939 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001940 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001941 if (paint.fColorMatrixEnabled) {
1942 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
1943 } else {
1944 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
1945 }
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);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001948 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001949
1950 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1951 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1952 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001953}
1954
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001955GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001956 DrawCategory category) {
1957 if (category != fLastDrawCategory) {
1958 flushDrawBuffer();
1959 fLastDrawCategory = category;
1960 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001961 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001962 GrDrawTarget* target = fGpu;
1963 switch (category) {
1964 case kText_DrawCategory:
1965#if DEFER_TEXT_RENDERING
1966 target = fDrawBuffer;
1967 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1968#else
1969 target = fGpu;
1970#endif
1971 break;
1972 case kUnbuffered_DrawCategory:
1973 target = fGpu;
1974 break;
1975 case kBuffered_DrawCategory:
1976 target = fDrawBuffer;
1977 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1978 break;
1979 }
1980 return target;
1981}
1982
bsalomon@google.com289533a2011-10-27 12:34:25 +00001983GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1984 GrPathFill fill,
1985 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001986 if (NULL == fPathRendererChain) {
1987 fPathRendererChain =
1988 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1989 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001990 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1991 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001992}
1993
bsalomon@google.com27847de2011-02-22 20:59:41 +00001994////////////////////////////////////////////////////////////////////////////////
1995
bsalomon@google.com27847de2011-02-22 20:59:41 +00001996void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001997 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001998 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001999 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002000}
2001
2002GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002003 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002004}
2005
2006const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002007 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002008}
2009
2010const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002011 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002012}
2013
2014void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002015 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002016}
2017
2018void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002019 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002020}
2021
2022static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2023 intptr_t mask = 1 << shift;
2024 if (pred) {
2025 bits |= mask;
2026 } else {
2027 bits &= ~mask;
2028 }
2029 return bits;
2030}
2031
2032void GrContext::resetStats() {
2033 fGpu->resetStats();
2034}
2035
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002036const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002037 return fGpu->getStats();
2038}
2039
2040void GrContext::printStats() const {
2041 fGpu->printStats();
2042}
2043
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002044GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002045 fGpu = gpu;
2046 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002047 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002048
bsalomon@google.com30085192011-08-19 15:42:31 +00002049 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002050
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002051 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2052 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002053 fFontCache = new GrFontCache(fGpu);
2054
2055 fLastDrawCategory = kUnbuffered_DrawCategory;
2056
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002057 fDrawBuffer = NULL;
2058 fDrawBufferVBAllocPool = NULL;
2059 fDrawBufferIBAllocPool = NULL;
2060
bsalomon@google.com205d4602011-04-25 12:43:45 +00002061 fAAFillRectIndexBuffer = NULL;
2062 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002063
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002064 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2065 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002066 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2067 }
2068 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002069
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002070 this->setupDrawBuffer();
2071}
2072
2073void GrContext::setupDrawBuffer() {
2074
2075 GrAssert(NULL == fDrawBuffer);
2076 GrAssert(NULL == fDrawBufferVBAllocPool);
2077 GrAssert(NULL == fDrawBufferIBAllocPool);
2078
bsalomon@google.com27847de2011-02-22 20:59:41 +00002079#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002080 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002081 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002082 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2083 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002084 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002085 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002086 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002087 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2088
bsalomon@google.com471d4712011-08-23 15:45:25 +00002089 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2090 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002091 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002092#endif
2093
2094#if BATCH_RECT_TO_RECT
2095 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2096#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002097}
2098
bsalomon@google.com27847de2011-02-22 20:59:41 +00002099GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2100 GrDrawTarget* target;
2101#if DEFER_TEXT_RENDERING
2102 target = prepareToDraw(paint, kText_DrawCategory);
2103#else
2104 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2105#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002106 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002107 return target;
2108}
2109
2110const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2111 return fGpu->getQuadIndexBuffer();
2112}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002113
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002114void GrContext::convolveInX(GrTexture* texture,
2115 const SkRect& rect,
2116 const float* kernel,
2117 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002118 ASSERT_OWNED_RESOURCE(texture);
2119
bsalomon@google.com99621082011-11-15 16:47:16 +00002120 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002121 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2122}
2123
2124void GrContext::convolveInY(GrTexture* texture,
2125 const SkRect& rect,
2126 const float* kernel,
2127 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002128 ASSERT_OWNED_RESOURCE(texture);
2129
bsalomon@google.com99621082011-11-15 16:47:16 +00002130 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002131 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2132}
2133
2134void GrContext::convolve(GrTexture* texture,
2135 const SkRect& rect,
2136 float imageIncrement[2],
2137 const float* kernel,
2138 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002139 ASSERT_OWNED_RESOURCE(texture);
2140
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002141 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002142 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002143 GrMatrix sampleM;
2144 sampleM.setIDiv(texture->width(), texture->height());
2145 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2146 GrSamplerState::kConvolution_Filter,
2147 sampleM);
2148 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2149 kernel,
2150 imageIncrement);
2151
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002152 drawState->setViewMatrix(GrMatrix::I());
2153 drawState->setTexture(0, texture);
2154 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002155 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002156 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2157}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002158
2159///////////////////////////////////////////////////////////////////////////////