blob: a798ec9ec2ee5e69ea4bef587f19224e65aa636e [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.com27847de2011-02-22 20:59:41 +0000372 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000373 filter);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000374 drawState->setSampler(0, stretchSampler);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000375
376 static const GrVertexLayout layout =
377 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
378 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
379
380 if (arg.succeeded()) {
381 GrPoint* verts = (GrPoint*) arg.vertices();
382 verts[0].setIRectFan(0, 0,
383 texture->width(),
384 texture->height(),
385 2*sizeof(GrPoint));
386 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
387 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
388 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000389 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000390 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000391 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000392 } else {
393 // TODO: Our CPU stretch doesn't filter. But we create separate
394 // stretched textures when the sampler state is either filtered or
395 // not. Either implement filtered stretch blit on CPU or just create
396 // one when FBO case fails.
397
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000398 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000399 // no longer need to clamp at min RT size.
400 rtDesc.fWidth = GrNextPow2(desc.fWidth);
401 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000402 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000403 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000404 rtDesc.fWidth *
405 rtDesc.fHeight);
406 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
407 srcData, desc.fWidth, desc.fHeight, bpp);
408
409 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
410
411 GrTexture* texture = fGpu->createTexture(rtDesc,
412 stretchedPixels.get(),
413 stretchedRowBytes);
414 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000415 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000416 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000417 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000418
419 } else {
420 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
421 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000422 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000423 }
424 }
425 return entry;
426}
427
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000428namespace {
429inline void gen_scratch_tex_key_values(const GrGpu* gpu,
430 const GrTextureDesc& desc,
431 uint32_t v[4]) {
432 // Instead of a client-provided key of the texture contents
433 // we create a key of from the descriptor.
434 GrContext::TextureKey descKey = desc.fAALevel |
435 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000436 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000437 // this code path isn't friendly to tiling with NPOT restricitons
438 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000439 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
440 desc.fHeight, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000442}
443
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000444GrContext::TextureCacheEntry GrContext::lockScratchTexture(
445 const GrTextureDesc& inDesc,
446 ScratchTexMatch match) {
447
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000448 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000449 if (kExact_ScratchTexMatch != match) {
450 // bin by pow2 with a reasonable min
451 static const int MIN_SIZE = 256;
452 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
453 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
454 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000455
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000456 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000457 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
458
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000459 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000460 int origWidth = desc.fWidth;
461 int origHeight = desc.fHeight;
462 bool doubledW = false;
463 bool doubledH = false;
464
465 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000466 uint32_t v[4];
467 gen_scratch_tex_key_values(fGpu, desc, v);
468 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000469 entry = fTextureCache->findAndLock(key,
470 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000471 // if we miss, relax the fit of the flags...
472 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000473 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000474 break;
475 }
476 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
477 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
478 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
479 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
480 } else if (!doubledW) {
481 desc.fFlags = inDesc.fFlags;
482 desc.fWidth *= 2;
483 doubledW = true;
484 } else if (!doubledH) {
485 desc.fFlags = inDesc.fFlags;
486 desc.fWidth = origWidth;
487 desc.fHeight *= 2;
488 doubledH = true;
489 } else {
490 break;
491 }
492
493 } while (true);
494
495 if (NULL == entry) {
496 desc.fFlags = inDesc.fFlags;
497 desc.fWidth = origWidth;
498 desc.fHeight = origHeight;
499 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
500 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000501 uint32_t v[4];
502 gen_scratch_tex_key_values(fGpu, desc, v);
503 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000504 entry = fTextureCache->createAndLock(key, texture);
505 }
506 }
507
508 // If the caller gives us the same desc/sampler twice we don't want
509 // to return the same texture the second time (unless it was previously
510 // released). So we detach the entry from the cache and reattach at release.
511 if (NULL != entry) {
512 fTextureCache->detach(entry);
513 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000514 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000515}
516
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000517void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000518 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000519 // If this is a scratch texture we detached it from the cache
520 // while it was locked (to avoid two callers simultaneously getting
521 // the same texture).
522 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
523 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000524 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000525 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000526 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000527}
528
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000529GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000530 void* srcData,
531 size_t rowBytes) {
532 return fGpu->createTexture(desc, srcData, rowBytes);
533}
534
535void GrContext::getTextureCacheLimits(int* maxTextures,
536 size_t* maxTextureBytes) const {
537 fTextureCache->getLimits(maxTextures, maxTextureBytes);
538}
539
540void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
541 fTextureCache->setLimits(maxTextures, maxTextureBytes);
542}
543
bsalomon@google.com91958362011-06-13 17:58:13 +0000544int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000545 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000546}
547
548int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000549 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000550}
551
552///////////////////////////////////////////////////////////////////////////////
553
bsalomon@google.come269f212011-11-07 13:29:52 +0000554GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
555 return fGpu->createPlatformTexture(desc);
556}
557
558GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
559 return fGpu->createPlatformRenderTarget(desc);
560}
561
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000562GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
563 // validate flags here so that GrGpu subclasses don't have to check
564 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
565 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000566 return NULL;
567 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000568 if (desc.fSampleCnt &&
569 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000570 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000571 }
572 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
573 desc.fSampleCnt &&
574 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
575 return NULL;
576 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000577 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000578}
579
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000580///////////////////////////////////////////////////////////////////////////////
581
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000582bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000583 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000584 const GrDrawTarget::Caps& caps = fGpu->getCaps();
585 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000586 return false;
587 }
588
bsalomon@google.com27847de2011-02-22 20:59:41 +0000589 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
590
591 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000592 bool tiled = NULL != sampler &&
593 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
594 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000595 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000596 return false;
597 }
598 }
599 return true;
600}
601
602////////////////////////////////////////////////////////////////////////////////
603
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000604const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
605
bsalomon@google.com27847de2011-02-22 20:59:41 +0000606void GrContext::setClip(const GrClip& clip) {
607 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000608 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000609}
610
611void GrContext::setClip(const GrIRect& rect) {
612 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000613 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000614 fGpu->setClip(clip);
615}
616
617////////////////////////////////////////////////////////////////////////////////
618
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000619void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000620 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000621 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000622}
623
624void GrContext::drawPaint(const GrPaint& paint) {
625 // set rect to be big enough to fill the space, but not super-huge, so we
626 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000627 GrRect r;
628 r.setLTRB(0, 0,
629 GrIntToScalar(getRenderTarget()->width()),
630 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000631 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000632 SkTLazy<GrPaint> tmpPaint;
633 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000634 GrDrawState* drawState = fGpu->drawState();
635 GrAutoMatrix am;
636
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000637 // We attempt to map r by the inverse matrix and draw that. mapRect will
638 // map the four corners and bound them with a new rect. This will not
639 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000640 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000641 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000642 GrPrintf("Could not invert matrix");
643 return;
644 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000645 inverse.mapRect(&r);
646 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000647 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000648 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000649 GrPrintf("Could not invert matrix");
650 return;
651 }
652 tmpPaint.set(paint);
653 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
654 p = tmpPaint.get();
655 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000656 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000657 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000658 // by definition this fills the entire clip, no need for AA
659 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000660 if (!tmpPaint.isValid()) {
661 tmpPaint.set(paint);
662 p = tmpPaint.get();
663 }
664 GrAssert(p == tmpPaint.get());
665 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000666 }
667 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000668}
669
bsalomon@google.com205d4602011-04-25 12:43:45 +0000670////////////////////////////////////////////////////////////////////////////////
671
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000672namespace {
673inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
674 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
675}
676}
677
bsalomon@google.com91958362011-06-13 17:58:13 +0000678struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000679 enum Downsample {
680 k4x4TwoPass_Downsample,
681 k4x4SinglePass_Downsample,
682 kFSAA_Downsample
683 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000684 int fTileSizeX;
685 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000686 int fTileCountX;
687 int fTileCountY;
688 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000689 GrAutoScratchTexture fOffscreen0;
690 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000691 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000692 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000693};
694
bsalomon@google.com471d4712011-08-23 15:45:25 +0000695bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000696 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000697#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000698 return false;
699#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000700 // Line primitves are always rasterized as 1 pixel wide.
701 // Super-sampling would make them too thin but MSAA would be OK.
702 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000703 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000704 return false;
705 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000706 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000707 return false;
708 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000709 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000710#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000711 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000712#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000713 return false;
714 }
715 return true;
716#endif
717}
718
bsalomon@google.com91958362011-06-13 17:58:13 +0000719bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000720 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000721 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000722 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000723 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000724
725 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000726
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000727 GrAssert(NULL == record->fOffscreen0.texture());
728 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000729 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000730
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000731 int boundW = boundRect.width();
732 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000733
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000734 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000735
736 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
737 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
738
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000739 if (requireStencil) {
740 desc.fFlags = kRenderTarget_GrTextureFlagBit;
741 } else {
742 desc.fFlags = kRenderTarget_GrTextureFlagBit |
743 kNoStencil_GrTextureFlagBit;
744 }
745
bsalomon@google.comc4364992011-11-07 15:54:49 +0000746 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000747
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000748 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000749 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000750 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000751 desc.fAALevel = kMed_GrAALevel;
752 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000753 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000754 OffscreenRecord::k4x4SinglePass_Downsample :
755 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000756 record->fScale = OFFSCREEN_SSAA_SCALE;
757 // both downsample paths assume this
758 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000759 desc.fAALevel = kNone_GrAALevel;
760 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000761
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000762 desc.fWidth *= record->fScale;
763 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000764 record->fOffscreen0.set(this, desc);
765 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000766 return false;
767 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000768 // the approximate lookup might have given us some slop space, might as well
769 // use it when computing the tiles size.
770 // these are scale values, will adjust after considering
771 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000772 record->fTileSizeX = record->fOffscreen0.texture()->width();
773 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000774
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000775 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000776 desc.fWidth /= 2;
777 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000778 record->fOffscreen1.set(this, desc);
779 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000780 return false;
781 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000782 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000783 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000784 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000785 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000786 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000787 record->fTileSizeX /= record->fScale;
788 record->fTileSizeY /= record->fScale;
789
790 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
791 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
792
tomhudson@google.com237a4612011-07-19 15:44:00 +0000793 record->fClip = target->getClip();
794
bsalomon@google.com91958362011-06-13 17:58:13 +0000795 target->saveCurrentDrawState(&record->fSavedState);
796 return true;
797}
798
799void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
800 const GrIRect& boundRect,
801 int tileX, int tileY,
802 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000803
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000804 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000805 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000806
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000807 GrPaint tempPaint;
808 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000809 this->setPaint(tempPaint, target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000810 GrDrawState* drawState = target->drawState();
811 drawState->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000812#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000813 target->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000814#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000815
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000816 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000817 int left = boundRect.fLeft + tileX * record->fTileSizeX;
818 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000819 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000820 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000821 GrMatrix scaleM;
822 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000823 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000824
bsalomon@google.com91958362011-06-13 17:58:13 +0000825 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000826 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000827 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000828 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000829 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
830 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000831 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000832#if 0
833 // visualize tile boundaries by setting edges of offscreen to white
834 // and interior to tranparent. black.
835 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000836
bsalomon@google.com91958362011-06-13 17:58:13 +0000837 static const int gOffset = 2;
838 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
839 record->fScale * w - gOffset,
840 record->fScale * h - gOffset);
841 target->clear(&clear2, 0x0);
842#else
843 target->clear(&clear, 0x0);
844#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000845}
846
bsalomon@google.com91958362011-06-13 17:58:13 +0000847void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000848 const GrPaint& paint,
849 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000850 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000851 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000852 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000853 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000854 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000855 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000856 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
857 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000858 tileRect.fRight = (tileX == record->fTileCountX-1) ?
859 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000860 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000861 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
862 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000863 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000864
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000865 GrSamplerState::Filter filter;
866 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
867 filter = GrSamplerState::k4x4Downsample_Filter;
868 } else {
869 filter = GrSamplerState::kBilinear_Filter;
870 }
871
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000872 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +0000873 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000874
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000875 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000876 int scale;
877
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000878 enum {
879 kOffscreenStage = GrPaint::kTotalStages,
880 };
881
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000882 GrDrawState* drawState = target->drawState();
883
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000884 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000885 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000886 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000887 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000888
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000889 // Do 2x2 downsample from first to second
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000890 drawState->setTexture(kOffscreenStage, src);
891 drawState->setRenderTarget(dst);
892 drawState->setViewMatrix(GrMatrix::I());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000893 sampleM.setScale(scale * GR_Scalar1 / src->width(),
894 scale * GR_Scalar1 / src->height());
895 sampler.setMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000896 drawState->setSampler(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000897 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
898 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000899 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
900
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000901 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000902 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000903 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000904 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000905 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000906 } else {
907 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
908 record->fDownsample);
909 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000910 }
911
bsalomon@google.com91958362011-06-13 17:58:13 +0000912 // setup for draw back to main RT, we use the original
913 // draw state setup by the caller plus an additional coverage
914 // stage to handle the AA resolve. Also, we use an identity
915 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000916 int stageMask = paint.getActiveStageMask();
917
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000918 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000919 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000920
921 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000922 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000923 if (drawState->getViewInverse(&invVM)) {
924 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000925 }
926 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000927 // This is important when tiling, otherwise second tile's
928 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000929 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000930
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000931 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000932 sampleM.setScale(scale * GR_Scalar1 / src->width(),
933 scale * GR_Scalar1 / src->height());
934 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000935 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
936 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000937 sampler.preConcatMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000938 drawState->setSampler(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000939
reed@google.com20efde72011-05-09 17:00:02 +0000940 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000941 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000942 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000943 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000944}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000945
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000946void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
947 GrPathRenderer* pr,
948 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000949 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000950}
951
952////////////////////////////////////////////////////////////////////////////////
953
bsalomon@google.com27847de2011-02-22 20:59:41 +0000954/* create a triangle strip that strokes the specified triangle. There are 8
955 unique vertices, but we repreat the last 2 to close up. Alternatively we
956 could use an indices array, and then only send 8 verts, but not sure that
957 would be faster.
958 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000959static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000960 GrScalar width) {
961 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000962 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000963
964 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
965 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
966 verts[2].set(rect.fRight - rad, rect.fTop + rad);
967 verts[3].set(rect.fRight + rad, rect.fTop - rad);
968 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
969 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
970 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
971 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
972 verts[8] = verts[0];
973 verts[9] = verts[1];
974}
975
bsalomon@google.com205d4602011-04-25 12:43:45 +0000976static void setInsetFan(GrPoint* pts, size_t stride,
977 const GrRect& r, GrScalar dx, GrScalar dy) {
978 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
979}
980
981static const uint16_t gFillAARectIdx[] = {
982 0, 1, 5, 5, 4, 0,
983 1, 2, 6, 6, 5, 1,
984 2, 3, 7, 7, 6, 2,
985 3, 0, 4, 4, 7, 3,
986 4, 5, 6, 6, 7, 4,
987};
988
989int GrContext::aaFillRectIndexCount() const {
990 return GR_ARRAY_COUNT(gFillAARectIdx);
991}
992
993GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
994 if (NULL == fAAFillRectIndexBuffer) {
995 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
996 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000997 if (NULL != fAAFillRectIndexBuffer) {
998 #if GR_DEBUG
999 bool updated =
1000 #endif
1001 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
1002 sizeof(gFillAARectIdx));
1003 GR_DEBUGASSERT(updated);
1004 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001005 }
1006 return fAAFillRectIndexBuffer;
1007}
1008
1009static const uint16_t gStrokeAARectIdx[] = {
1010 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
1011 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1012 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1013 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1014
1015 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1016 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1017 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1018 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1019
1020 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1021 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1022 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1023 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1024};
1025
1026int GrContext::aaStrokeRectIndexCount() const {
1027 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1028}
1029
1030GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1031 if (NULL == fAAStrokeRectIndexBuffer) {
1032 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1033 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001034 if (NULL != fAAStrokeRectIndexBuffer) {
1035 #if GR_DEBUG
1036 bool updated =
1037 #endif
1038 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1039 sizeof(gStrokeAARectIdx));
1040 GR_DEBUGASSERT(updated);
1041 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001042 }
1043 return fAAStrokeRectIndexBuffer;
1044}
1045
bsalomon@google.coma3108262011-10-10 14:08:47 +00001046static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1047 bool useCoverage) {
1048 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001049 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001050 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001051 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1052 }
1053 }
1054 if (useCoverage) {
1055 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1056 } else {
1057 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1058 }
1059 return layout;
1060}
1061
bsalomon@google.com205d4602011-04-25 12:43:45 +00001062void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001063 const GrRect& devRect,
1064 bool useVertexCoverage) {
1065 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001066
1067 size_t vsize = GrDrawTarget::VertexSize(layout);
1068
1069 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001070 if (!geo.succeeded()) {
1071 GrPrintf("Failed to get space for vertices!\n");
1072 return;
1073 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001074 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1075 if (NULL == indexBuffer) {
1076 GrPrintf("Failed to create index buffer!\n");
1077 return;
1078 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001079
1080 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1081
1082 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1083 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1084
1085 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1086 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1087
1088 verts += sizeof(GrPoint);
1089 for (int i = 0; i < 4; ++i) {
1090 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1091 }
1092
bsalomon@google.coma3108262011-10-10 14:08:47 +00001093 GrColor innerColor;
1094 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001095 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001096 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001097 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001098 }
1099
bsalomon@google.com205d4602011-04-25 12:43:45 +00001100 verts += 4 * vsize;
1101 for (int i = 0; i < 4; ++i) {
1102 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1103 }
1104
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001105 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001106
1107 target->drawIndexed(kTriangles_PrimitiveType, 0,
1108 0, 8, this->aaFillRectIndexCount());
1109}
1110
bsalomon@google.coma3108262011-10-10 14:08:47 +00001111void GrContext::strokeAARect(GrDrawTarget* target,
1112 const GrRect& devRect,
1113 const GrVec& devStrokeSize,
1114 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001115 const GrScalar& dx = devStrokeSize.fX;
1116 const GrScalar& dy = devStrokeSize.fY;
1117 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1118 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1119
bsalomon@google.com205d4602011-04-25 12:43:45 +00001120 GrScalar spare;
1121 {
1122 GrScalar w = devRect.width() - dx;
1123 GrScalar h = devRect.height() - dy;
1124 spare = GrMin(w, h);
1125 }
1126
1127 if (spare <= 0) {
1128 GrRect r(devRect);
1129 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001130 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001131 return;
1132 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001133 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001134 size_t vsize = GrDrawTarget::VertexSize(layout);
1135
1136 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001137 if (!geo.succeeded()) {
1138 GrPrintf("Failed to get space for vertices!\n");
1139 return;
1140 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001141 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1142 if (NULL == indexBuffer) {
1143 GrPrintf("Failed to create index buffer!\n");
1144 return;
1145 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001146
1147 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1148
1149 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1150 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1151 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1152 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1153
1154 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1155 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1156 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1157 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1158
1159 verts += sizeof(GrPoint);
1160 for (int i = 0; i < 4; ++i) {
1161 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1162 }
1163
bsalomon@google.coma3108262011-10-10 14:08:47 +00001164 GrColor innerColor;
1165 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001166 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001167 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001168 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001169 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001170 verts += 4 * vsize;
1171 for (int i = 0; i < 8; ++i) {
1172 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1173 }
1174
1175 verts += 8 * vsize;
1176 for (int i = 0; i < 8; ++i) {
1177 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1178 }
1179
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001180 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001181 target->drawIndexed(kTriangles_PrimitiveType,
1182 0, 0, 16, aaStrokeRectIndexCount());
1183}
1184
reed@google.com20efde72011-05-09 17:00:02 +00001185/**
1186 * Returns true if the rects edges are integer-aligned.
1187 */
1188static bool isIRect(const GrRect& r) {
1189 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1190 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1191}
1192
bsalomon@google.com205d4602011-04-25 12:43:45 +00001193static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001194 const GrRect& rect,
1195 GrScalar width,
1196 const GrMatrix* matrix,
1197 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001198 GrRect* devRect,
1199 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001200 // we use a simple alpha ramp to do aa on axis-aligned rects
1201 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001202 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001203
bsalomon@google.coma3108262011-10-10 14:08:47 +00001204 // we are keeping around the "tweak the alpha" trick because
1205 // it is our only hope for the fixed-pipe implementation.
1206 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001207 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001208 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001209 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001210 if (target->getCaps().fSupportPerVertexCoverage) {
1211 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001212#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001213 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001214#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001215 return false;
1216 } else {
1217 *useVertexCoverage = true;
1218 }
1219 } else {
1220 GrPrintf("Rect AA dropped because no support for coverage.\n");
1221 return false;
1222 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001223 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001224 const GrDrawState& drawState = target->getDrawState();
1225 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001226 return false;
1227 }
1228
bsalomon@google.com471d4712011-08-23 15:45:25 +00001229 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001230 return false;
1231 }
1232
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001233 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001234 return false;
1235 }
1236
1237 if (NULL != matrix &&
1238 !matrix->preservesAxisAlignment()) {
1239 return false;
1240 }
1241
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001242 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001243 if (NULL != matrix) {
1244 combinedMatrix->preConcat(*matrix);
1245 GrAssert(combinedMatrix->preservesAxisAlignment());
1246 }
1247
1248 combinedMatrix->mapRect(devRect, rect);
1249 devRect->sort();
1250
1251 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001252 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001253 } else {
1254 return true;
1255 }
1256}
1257
bsalomon@google.com27847de2011-02-22 20:59:41 +00001258void GrContext::drawRect(const GrPaint& paint,
1259 const GrRect& rect,
1260 GrScalar width,
1261 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001262 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001263
1264 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001265 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001266
bsalomon@google.com205d4602011-04-25 12:43:45 +00001267 GrRect devRect = rect;
1268 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001269 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001270 bool needAA = paint.fAntiAlias &&
1271 !this->getRenderTarget()->isMultisampled();
1272 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1273 &combinedMatrix, &devRect,
1274 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001275
1276 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001277 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001278 if (width >= 0) {
1279 GrVec strokeSize;;
1280 if (width > 0) {
1281 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001282 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001283 strokeSize.setAbs(strokeSize);
1284 } else {
1285 strokeSize.set(GR_Scalar1, GR_Scalar1);
1286 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001287 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001288 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001289 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001290 }
1291 return;
1292 }
1293
bsalomon@google.com27847de2011-02-22 20:59:41 +00001294 if (width >= 0) {
1295 // TODO: consider making static vertex buffers for these cases.
1296 // Hairline could be done by just adding closing vertex to
1297 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001298 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1299
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300 static const int worstCaseVertCount = 10;
1301 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1302
1303 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001304 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001305 return;
1306 }
1307
1308 GrPrimitiveType primType;
1309 int vertCount;
1310 GrPoint* vertex = geo.positions();
1311
1312 if (width > 0) {
1313 vertCount = 10;
1314 primType = kTriangleStrip_PrimitiveType;
1315 setStrokeRectStrip(vertex, rect, width);
1316 } else {
1317 // hairline
1318 vertCount = 5;
1319 primType = kLineStrip_PrimitiveType;
1320 vertex[0].set(rect.fLeft, rect.fTop);
1321 vertex[1].set(rect.fRight, rect.fTop);
1322 vertex[2].set(rect.fRight, rect.fBottom);
1323 vertex[3].set(rect.fLeft, rect.fBottom);
1324 vertex[4].set(rect.fLeft, rect.fTop);
1325 }
1326
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001327 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001328 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001329 GrDrawState* drawState = target->drawState();
1330 avmr.set(drawState);
1331 drawState->preConcatViewMatrix(*matrix);
1332 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001333 }
1334
1335 target->drawNonIndexed(primType, 0, vertCount);
1336 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001337#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001338 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001339 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1340 if (NULL == sqVB) {
1341 GrPrintf("Failed to create static rect vb.\n");
1342 return;
1343 }
1344 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001345 GrDrawState* drawState = target->drawState();
1346 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001347 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001348 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001349 0, rect.height(), rect.fTop,
1350 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001351
1352 if (NULL != matrix) {
1353 m.postConcat(*matrix);
1354 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001355 drawState->preConcatViewMatrix(m);
1356 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001357
bsalomon@google.com27847de2011-02-22 20:59:41 +00001358 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001359#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001360 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001361#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001362 }
1363}
1364
1365void GrContext::drawRectToRect(const GrPaint& paint,
1366 const GrRect& dstRect,
1367 const GrRect& srcRect,
1368 const GrMatrix* dstMatrix,
1369 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001370 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001371
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001372 // srcRect refers to paint's first texture
1373 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001374 drawRect(paint, dstRect, -1, dstMatrix);
1375 return;
1376 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001377
bsalomon@google.com27847de2011-02-22 20:59:41 +00001378 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1379
1380#if GR_STATIC_RECT_VB
1381 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001382 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001383 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001384 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001385
1386 GrMatrix m;
1387
1388 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1389 0, dstRect.height(), dstRect.fTop,
1390 0, 0, GrMatrix::I()[8]);
1391 if (NULL != dstMatrix) {
1392 m.postConcat(*dstMatrix);
1393 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001394 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001396 // srcRect refers to first stage
1397 int otherStageMask = paint.getActiveStageMask() &
1398 (~(1 << GrPaint::kFirstTextureStage));
1399 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001400 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001401 }
1402
bsalomon@google.com27847de2011-02-22 20:59:41 +00001403 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1404 0, srcRect.height(), srcRect.fTop,
1405 0, 0, GrMatrix::I()[8]);
1406 if (NULL != srcMatrix) {
1407 m.postConcat(*srcMatrix);
1408 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001409 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001411 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1412 if (NULL == sqVB) {
1413 GrPrintf("Failed to create static rect vb.\n");
1414 return;
1415 }
1416 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1418#else
1419
1420 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001421#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001422 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001423#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001424 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1425#endif
1426
tomhudson@google.com93813632011-10-27 20:21:16 +00001427 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1428 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001429 srcRects[0] = &srcRect;
1430 srcMatrices[0] = srcMatrix;
1431
1432 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1433#endif
1434}
1435
1436void GrContext::drawVertices(const GrPaint& paint,
1437 GrPrimitiveType primitiveType,
1438 int vertexCount,
1439 const GrPoint positions[],
1440 const GrPoint texCoords[],
1441 const GrColor colors[],
1442 const uint16_t indices[],
1443 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001444 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001445
1446 GrDrawTarget::AutoReleaseGeometry geo;
1447
1448 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1449
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001450 bool hasTexCoords[GrPaint::kTotalStages] = {
1451 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1452 0 // remaining stages use positions
1453 };
1454
1455 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001456
1457 if (NULL != colors) {
1458 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001459 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001460 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001461
1462 if (sizeof(GrPoint) != vertexSize) {
1463 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001464 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001465 return;
1466 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001467 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001468 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001469 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1470 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001471 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001472 NULL,
1473 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001474 void* curVertex = geo.vertices();
1475
1476 for (int i = 0; i < vertexCount; ++i) {
1477 *((GrPoint*)curVertex) = positions[i];
1478
1479 if (texOffsets[0] > 0) {
1480 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1481 }
1482 if (colorOffset > 0) {
1483 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1484 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001485 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001486 }
1487 } else {
1488 target->setVertexSourceToArray(layout, positions, vertexCount);
1489 }
1490
bsalomon@google.com91958362011-06-13 17:58:13 +00001491 // we don't currently apply offscreen AA to this path. Need improved
1492 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001493
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001494 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001495 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001496 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001497 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001498 target->drawNonIndexed(primitiveType, 0, vertexCount);
1499 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001500}
1501
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001502///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001503
reed@google.com07f3ee12011-05-16 17:21:57 +00001504void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1505 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001506
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001507 if (path.isEmpty()) {
1508#if GR_DEBUG
1509 GrPrintf("Empty path should have been caught by canvas.\n");
1510#endif
1511 if (GrIsFillInverted(fill)) {
1512 this->drawPaint(paint);
1513 }
1514 return;
1515 }
1516
bsalomon@google.com27847de2011-02-22 20:59:41 +00001517 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001518
bsalomon@google.com289533a2011-10-27 12:34:25 +00001519 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1520
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001521 // An Assumption here is that path renderer would use some form of tweaking
1522 // the src color (either the input alpha or in the frag shader) to implement
1523 // aa. If we have some future driver-mojo path AA that can do the right
1524 // thing WRT to the blend then we'll need some query on the PR.
1525 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001526#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001527 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001528#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001529 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001530 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001531
1532 bool doOSAA = false;
1533 GrPathRenderer* pr = NULL;
1534 if (prAA) {
1535 pr = this->getPathRenderer(path, fill, true);
1536 if (NULL == pr) {
1537 prAA = false;
1538 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1539 pr = this->getPathRenderer(path, fill, false);
1540 }
1541 } else {
1542 pr = this->getPathRenderer(path, fill, false);
1543 }
1544
bsalomon@google.com30085192011-08-19 15:42:31 +00001545 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001546#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001547 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001548#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001549 return;
1550 }
1551
bsalomon@google.com289533a2011-10-27 12:34:25 +00001552 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001553 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001554
bsalomon@google.com289533a2011-10-27 12:34:25 +00001555 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001556 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001557 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001558 // compute bounds as intersection of rt size, clip, and path
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001559 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001560 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001561 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001562 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001563 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001564 return;
1565 }
1566 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001567 GrRect pathBounds = path.getBounds();
1568 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001569 if (NULL != translate) {
1570 pathBounds.offset(*translate);
1571 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001572 target->getDrawState().getViewMatrix().mapRect(&pathBounds,
1573 pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001574 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001575 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001576 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001577 return;
1578 }
1579 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001580 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001581 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1582 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001583 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1584 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1585 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001586 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001587 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1588 }
1589 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001590 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001591 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001592 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1593 GrRect rect;
1594 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001595 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1596 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001597 target->drawSimpleRect(rect, NULL, stageMask);
1598 }
1599 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001600 rect.iset(clipIBounds.fLeft, bound.fTop,
1601 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001602 target->drawSimpleRect(rect, NULL, stageMask);
1603 }
1604 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001605 rect.iset(bound.fRight, bound.fTop,
1606 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001607 target->drawSimpleRect(rect, NULL, stageMask);
1608 }
1609 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001610 rect.iset(clipIBounds.fLeft, bound.fBottom,
1611 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001612 target->drawSimpleRect(rect, NULL, stageMask);
1613 }
1614 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001615 return;
1616 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001617 }
1618 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001619}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001620
bsalomon@google.com27847de2011-02-22 20:59:41 +00001621////////////////////////////////////////////////////////////////////////////////
1622
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001623bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001624 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001625}
1626
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001627void GrContext::flush(int flagsBitfield) {
1628 if (kDiscard_FlushBit & flagsBitfield) {
1629 fDrawBuffer->reset();
1630 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001631 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001632 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001633 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001634 fGpu->forceRenderTargetFlush();
1635 }
1636}
1637
1638void GrContext::flushText() {
1639 if (kText_DrawCategory == fLastDrawCategory) {
1640 flushDrawBuffer();
1641 }
1642}
1643
1644void GrContext::flushDrawBuffer() {
1645#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001646 if (fDrawBuffer) {
1647 fDrawBuffer->playback(fGpu);
1648 fDrawBuffer->reset();
1649 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001650#endif
1651}
1652
bsalomon@google.com6f379512011-11-16 20:36:03 +00001653void GrContext::internalWriteTexturePixels(GrTexture* texture,
1654 int left, int top,
1655 int width, int height,
1656 GrPixelConfig config,
1657 const void* buffer,
1658 size_t rowBytes,
1659 uint32_t flags) {
1660 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001661 ASSERT_OWNED_RESOURCE(texture);
1662
bsalomon@google.com6f379512011-11-16 20:36:03 +00001663 if (!(kDontFlush_PixelOpsFlag & flags)) {
1664 this->flush();
1665 }
1666 // TODO: use scratch texture to perform conversion
1667 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1668 GrPixelConfigIsUnpremultiplied(config)) {
1669 return;
1670 }
1671
1672 fGpu->writeTexturePixels(texture, left, top, width, height,
1673 config, buffer, rowBytes);
1674}
1675
1676bool GrContext::internalReadTexturePixels(GrTexture* texture,
1677 int left, int top,
1678 int width, int height,
1679 GrPixelConfig config,
1680 void* buffer,
1681 size_t rowBytes,
1682 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001683 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001684 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001685
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001686 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001687 GrRenderTarget* target = texture->asRenderTarget();
1688 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001689 return this->internalReadRenderTargetPixels(target,
1690 left, top, width, height,
1691 config, buffer, rowBytes,
1692 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001693 } else {
1694 return false;
1695 }
1696}
1697
bsalomon@google.com6f379512011-11-16 20:36:03 +00001698bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1699 int left, int top,
1700 int width, int height,
1701 GrPixelConfig config,
1702 void* buffer,
1703 size_t rowBytes,
1704 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001705 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001706 ASSERT_OWNED_RESOURCE(target);
1707
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001708 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001709 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001710 if (NULL == target) {
1711 return false;
1712 }
1713 }
1714
1715 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1716 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1717 // not supported at this time.
1718 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1719 !GrPixelConfigIsUnpremultiplied(config)) {
1720 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001721 }
1722
bsalomon@google.com6f379512011-11-16 20:36:03 +00001723 if (!(kDontFlush_PixelOpsFlag & flags)) {
1724 this->flush();
1725 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001726
1727 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001728 bool swapRAndB = NULL != src &&
1729 fGpu->preferredReadPixelsConfig(config) ==
1730 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001731
1732 bool flipY = NULL != src &&
1733 fGpu->readPixelsWillPayForYFlip(target, left, top,
1734 width, height, config,
1735 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001736 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1737 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001738
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001739 if (NULL == src && alphaConversion) {
1740 // we should fallback to cpu conversion here. This could happen when
1741 // we were given an external render target by the client that is not
1742 // also a texture (e.g. FBO 0 in GL)
1743 return false;
1744 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001745 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001746 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001747 if (flipY || swapRAndB || alphaConversion) {
1748 GrAssert(NULL != src);
1749 if (swapRAndB) {
1750 config = GrPixelConfigSwapRAndB(config);
1751 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001752 }
1753 // Make the scratch a render target because we don't have a robust
1754 // readTexturePixels as of yet (it calls this function).
1755 const GrTextureDesc desc = {
1756 kRenderTarget_GrTextureFlagBit,
1757 kNone_GrAALevel,
1758 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001759 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001760 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001761
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001762 // When a full readback is faster than a partial we could always make
1763 // the scratch exactly match the passed rect. However, if we see many
1764 // different size rectangles we will trash our texture cache and pay the
1765 // cost of creating and destroying many textures. So, we only request
1766 // an exact match when the caller is reading an entire RT.
1767 ScratchTexMatch match = kApprox_ScratchTexMatch;
1768 if (0 == left &&
1769 0 == top &&
1770 target->width() == width &&
1771 target->height() == height &&
1772 fGpu->fullReadPixelsIsFasterThanPartial()) {
1773 match = kExact_ScratchTexMatch;
1774 }
1775 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001776 GrTexture* texture = ast.texture();
1777 if (!texture) {
1778 return false;
1779 }
1780 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001781 GrAssert(NULL != target);
1782
1783 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001784 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001785 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001786 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001787
bsalomon@google.comc4364992011-11-07 15:54:49 +00001788 GrMatrix matrix;
1789 if (flipY) {
1790 matrix.setTranslate(SK_Scalar1 * left,
1791 SK_Scalar1 * (top + height));
1792 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1793 } else {
1794 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1795 }
1796 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001797 GrSamplerState sampler;
1798 sampler.reset(GrSamplerState::kClamp_WrapMode,
1799 GrSamplerState::kNearest_Filter,
1800 matrix);
1801 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001802 drawState->setSampler(0, sampler);
1803 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001804 GrRect rect;
1805 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1806 fGpu->drawSimpleRect(rect, NULL, 0x1);
1807 left = 0;
1808 top = 0;
1809 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001810 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001811 left, top, width, height,
1812 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001813}
1814
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001815void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1816 if (NULL == src || NULL == dst) {
1817 return;
1818 }
1819 ASSERT_OWNED_RESOURCE(src);
1820
1821 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001822 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001823 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001824 drawState->setRenderTarget(dst);
bsalomon@google.com97912912011-12-06 16:30:36 +00001825 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001826 GrSamplerState::kNearest_Filter);
1827 GrMatrix sampleM;
1828 sampleM.setIDiv(src->width(), src->height());
1829 sampler.setMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001830 drawState->setTexture(0, src);
1831 drawState->setSampler(0, sampler);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001832 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1833 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1834}
1835
bsalomon@google.com6f379512011-11-16 20:36:03 +00001836void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1837 int left, int top,
1838 int width, int height,
1839 GrPixelConfig config,
1840 const void* buffer,
1841 size_t rowBytes,
1842 uint32_t flags) {
1843 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001844 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001845
1846 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001847 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001848 if (NULL == target) {
1849 return;
1850 }
1851 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001852
1853 // TODO: when underlying api has a direct way to do this we should use it
1854 // (e.g. glDrawPixels on desktop GL).
1855
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001856 // If the RT is also a texture and we don't have to do PM/UPM conversion
1857 // then take the texture path, which we expect to be at least as fast or
1858 // faster since it doesn't use an intermediate texture as we do below.
1859
1860#if !GR_MAC_BUILD
1861 // At least some drivers on the Mac get confused when glTexImage2D is called
1862 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1863 // determine what OS versions and/or HW is affected.
1864 if (NULL != target->asTexture() &&
1865 GrPixelConfigIsUnpremultiplied(target->config()) ==
1866 GrPixelConfigIsUnpremultiplied(config)) {
1867
1868 this->internalWriteTexturePixels(target->asTexture(),
1869 left, top, width, height,
1870 config, buffer, rowBytes, flags);
1871 return;
1872 }
1873#endif
1874
1875 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1876 GrPixelConfigSwapRAndB(config);
1877 if (swapRAndB) {
1878 config = GrPixelConfigSwapRAndB(config);
1879 }
1880
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001881 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001882 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001883 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001884 GrAutoScratchTexture ast(this, desc);
1885 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001886 if (NULL == texture) {
1887 return;
1888 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001889 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1890 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001891
bsalomon@google.com27847de2011-02-22 20:59:41 +00001892 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001893 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001894 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001895
1896 GrMatrix matrix;
1897 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001898 drawState->setViewMatrix(matrix);
1899 drawState->setRenderTarget(target);
1900 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001901
bsalomon@google.com5c638652011-07-18 19:31:59 +00001902 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001903 GrSamplerState sampler;
1904 sampler.reset(GrSamplerState::kClamp_WrapMode,
1905 GrSamplerState::kNearest_Filter,
1906 matrix);
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001907 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001908 drawState->setSampler(0, sampler);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001909
1910 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1911 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001912 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001913 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1914 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001915 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001916 return;
1917 }
1918 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1919 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1920}
1921////////////////////////////////////////////////////////////////////////////////
1922
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001923void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001924 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001925
1926 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1927 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001928 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001929 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001930 drawState->setSampler(s, paint.getTextureSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001931 }
1932
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001933 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001934
1935 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1936 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001937 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001938 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001939 drawState->setSampler(s, paint.getMaskSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001940 }
1941
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001942 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001943
1944 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001945 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001947 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001948 }
1949 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001950 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001951 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001952 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001953 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001954 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001955 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001956
1957 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1958 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1959 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001960}
1961
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001962GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001963 DrawCategory category) {
1964 if (category != fLastDrawCategory) {
1965 flushDrawBuffer();
1966 fLastDrawCategory = category;
1967 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001968 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001969 GrDrawTarget* target = fGpu;
1970 switch (category) {
1971 case kText_DrawCategory:
1972#if DEFER_TEXT_RENDERING
1973 target = fDrawBuffer;
1974 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1975#else
1976 target = fGpu;
1977#endif
1978 break;
1979 case kUnbuffered_DrawCategory:
1980 target = fGpu;
1981 break;
1982 case kBuffered_DrawCategory:
1983 target = fDrawBuffer;
1984 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1985 break;
1986 }
1987 return target;
1988}
1989
bsalomon@google.com289533a2011-10-27 12:34:25 +00001990GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1991 GrPathFill fill,
1992 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001993 if (NULL == fPathRendererChain) {
1994 fPathRendererChain =
1995 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1996 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001997 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1998 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001999}
2000
bsalomon@google.com27847de2011-02-22 20:59:41 +00002001////////////////////////////////////////////////////////////////////////////////
2002
bsalomon@google.com27847de2011-02-22 20:59:41 +00002003void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002004 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002005 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002006 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002007}
2008
2009GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002010 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002011}
2012
2013const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002014 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002015}
2016
2017const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002018 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002019}
2020
2021void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002022 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002023}
2024
2025void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002026 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002027}
2028
2029static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2030 intptr_t mask = 1 << shift;
2031 if (pred) {
2032 bits |= mask;
2033 } else {
2034 bits &= ~mask;
2035 }
2036 return bits;
2037}
2038
2039void GrContext::resetStats() {
2040 fGpu->resetStats();
2041}
2042
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002043const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002044 return fGpu->getStats();
2045}
2046
2047void GrContext::printStats() const {
2048 fGpu->printStats();
2049}
2050
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002051GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002052 fGpu = gpu;
2053 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002054 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002055
bsalomon@google.com30085192011-08-19 15:42:31 +00002056 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002057
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002058 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2059 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002060 fFontCache = new GrFontCache(fGpu);
2061
2062 fLastDrawCategory = kUnbuffered_DrawCategory;
2063
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002064 fDrawBuffer = NULL;
2065 fDrawBufferVBAllocPool = NULL;
2066 fDrawBufferIBAllocPool = NULL;
2067
bsalomon@google.com205d4602011-04-25 12:43:45 +00002068 fAAFillRectIndexBuffer = NULL;
2069 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002070
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002071 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2072 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002073 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2074 }
2075 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002076
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002077 this->setupDrawBuffer();
2078}
2079
2080void GrContext::setupDrawBuffer() {
2081
2082 GrAssert(NULL == fDrawBuffer);
2083 GrAssert(NULL == fDrawBufferVBAllocPool);
2084 GrAssert(NULL == fDrawBufferIBAllocPool);
2085
bsalomon@google.com27847de2011-02-22 20:59:41 +00002086#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002087 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002088 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002089 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2090 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002091 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002092 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002093 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002094 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2095
bsalomon@google.com471d4712011-08-23 15:45:25 +00002096 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2097 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002098 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002099#endif
2100
2101#if BATCH_RECT_TO_RECT
2102 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2103#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002104}
2105
bsalomon@google.com27847de2011-02-22 20:59:41 +00002106GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2107 GrDrawTarget* target;
2108#if DEFER_TEXT_RENDERING
2109 target = prepareToDraw(paint, kText_DrawCategory);
2110#else
2111 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2112#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002113 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002114 return target;
2115}
2116
2117const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2118 return fGpu->getQuadIndexBuffer();
2119}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002120
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002121void GrContext::convolveInX(GrTexture* texture,
2122 const SkRect& rect,
2123 const float* kernel,
2124 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002125 ASSERT_OWNED_RESOURCE(texture);
2126
bsalomon@google.com99621082011-11-15 16:47:16 +00002127 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002128 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2129}
2130
2131void GrContext::convolveInY(GrTexture* texture,
2132 const SkRect& rect,
2133 const float* kernel,
2134 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002135 ASSERT_OWNED_RESOURCE(texture);
2136
bsalomon@google.com99621082011-11-15 16:47:16 +00002137 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002138 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2139}
2140
2141void GrContext::convolve(GrTexture* texture,
2142 const SkRect& rect,
2143 float imageIncrement[2],
2144 const float* kernel,
2145 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002146 ASSERT_OWNED_RESOURCE(texture);
2147
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002148 GrDrawTarget::AutoStateRestore asr(fGpu);
2149 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +00002150 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002151 GrSamplerState::kConvolution_Filter);
2152 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002153 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002154 sampler.setMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002155 GrDrawState* drawState = fGpu->drawState();
2156 drawState->setSampler(0, sampler);
2157 drawState->setViewMatrix(GrMatrix::I());
2158 drawState->setTexture(0, texture);
2159 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002160 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002161 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2162}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002163
2164///////////////////////////////////////////////////////////////////////////////