blob: d9b9f08ec6eb03e668ff251948002064677f4a63 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.com1fadb202011-12-12 16:10:08 +000010#include "GrContext.h"
11
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000014#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015#include "GrIndexBuffer.h"
16#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000017#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000018#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000020#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000021#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000022#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000023#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024
bsalomon@google.com91958362011-06-13 17:58:13 +000025// Using MSAA seems to be slower for some yet unknown reason.
26#define PREFER_MSAA_OFFSCREEN_AA 0
27#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000028
bsalomon@google.com27847de2011-02-22 20:59:41 +000029#define DEFER_TEXT_RENDERING 1
30
31#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
32
bsalomon@google.comd46e2422011-09-23 17:40:07 +000033// When we're using coverage AA but the blend is incompatible (given gpu
34// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000035#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000036
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000037static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000039
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
bsalomon@google.combc4b6542011-11-19 13:56:11 +000048#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
49
bsalomon@google.com05ef5102011-05-02 21:14:59 +000050GrContext* GrContext::Create(GrEngine engine,
51 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000052 GrContext* ctx = NULL;
53 GrGpu* fGpu = GrGpu::Create(engine, context3D);
54 if (NULL != fGpu) {
55 ctx = new GrContext(fGpu);
56 fGpu->unref();
57 }
58 return ctx;
59}
60
bsalomon@google.com27847de2011-02-22 20:59:41 +000061GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000062 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000063 delete fTextureCache;
64 delete fFontCache;
65 delete fDrawBuffer;
66 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000067 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000068
bsalomon@google.com205d4602011-04-25 12:43:45 +000069 GrSafeUnref(fAAFillRectIndexBuffer);
70 GrSafeUnref(fAAStrokeRectIndexBuffer);
71 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000072 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000073}
74
bsalomon@google.com8fe72472011-03-30 21:26:44 +000075void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000076 contextDestroyed();
77 this->setupDrawBuffer();
78}
79
80void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 // abandon first to so destructors
82 // don't try to free the resources in the API.
83 fGpu->abandonResources();
84
bsalomon@google.com30085192011-08-19 15:42:31 +000085 // a path renderer may be holding onto resources that
86 // are now unusable
87 GrSafeSetNull(fPathRendererChain);
88
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBuffer;
90 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferVBAllocPool;
93 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000094
bsalomon@google.com8fe72472011-03-30 21:26:44 +000095 delete fDrawBufferIBAllocPool;
96 fDrawBufferIBAllocPool = NULL;
97
bsalomon@google.com205d4602011-04-25 12:43:45 +000098 GrSafeSetNull(fAAFillRectIndexBuffer);
99 GrSafeSetNull(fAAStrokeRectIndexBuffer);
100
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101 fTextureCache->removeAll();
102 fFontCache->freeAll();
103 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000104}
105
106void GrContext::resetContext() {
107 fGpu->markContextDirty();
108}
109
110void GrContext::freeGpuResources() {
111 this->flush();
112 fTextureCache->removeAll();
113 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000114 // a path renderer may be holding onto resources
115 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000116}
117
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000118////////////////////////////////////////////////////////////////////////////////
119
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000120int GrContext::PaintStageVertexLayoutBits(
121 const GrPaint& paint,
122 const bool hasTexCoords[GrPaint::kTotalStages]) {
123 int stageMask = paint.getActiveStageMask();
124 int layout = 0;
125 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
126 if ((1 << i) & stageMask) {
127 if (NULL != hasTexCoords && hasTexCoords[i]) {
128 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
129 } else {
130 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
131 }
132 }
133 }
134 return layout;
135}
136
137
138////////////////////////////////////////////////////////////////////////////////
139
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000140enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000141 // flags for textures
142 kNPOTBit = 0x1,
143 kFilterBit = 0x2,
144 kScratchBit = 0x4,
145
146 // resource type
147 kTextureBit = 0x8,
148 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000149};
150
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000151GrTexture* GrContext::TextureCacheEntry::texture() const {
152 if (NULL == fEntry) {
153 return NULL;
154 } else {
155 return (GrTexture*) fEntry->resource();
156 }
157}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000158
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000159namespace {
160// returns true if this is a "special" texture because of gpu NPOT limitations
161bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000162 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163 GrContext::TextureKey clientKey,
164 int width,
165 int height,
166 bool scratch,
167 uint32_t v[4]) {
168 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
169 // we assume we only need 16 bits of width and height
170 // assert that texture creation will fail anyway if this assumption
171 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000172 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000173 v[0] = clientKey & 0xffffffffUL;
174 v[1] = (clientKey >> 32) & 0xffffffffUL;
175 v[2] = width | (height << 16);
176
177 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000178 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000179 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
180
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000181 bool tiled = NULL != sampler &&
182 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
183 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000184
185 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000187 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000188 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000189 }
190 }
191 }
192
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000193 if (scratch) {
194 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000195 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000197 v[3] |= kTextureBit;
198
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199 return v[3] & kNPOTBit;
200}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000201
202// we should never have more than one stencil buffer with same combo of
203// (width,height,samplecount)
204void gen_stencil_key_values(int width, int height,
205 int sampleCnt, uint32_t v[4]) {
206 v[0] = width;
207 v[1] = height;
208 v[2] = sampleCnt;
209 v[3] = kStencilBufferBit;
210}
211
212void gen_stencil_key_values(const GrStencilBuffer* sb,
213 uint32_t v[4]) {
214 gen_stencil_key_values(sb->width(), sb->height(),
215 sb->numSamples(), v);
216}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000217
218// This should be subsumed by a future version of GrDrawState
219// It does not reset stage textures/samplers or per-vertex-edge-aa state since
220// they aren't used unless the vertex layout references them.
221// It also doesn't set the render target.
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000222void reset_draw_state(GrDrawState* drawState){
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000223
224 drawState->setViewMatrix(GrMatrix::I());
225 drawState->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000226 drawState->resetStateFlags();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000227 drawState->setEdgeAAData(NULL, 0);
228 drawState->disableStencil();
229 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000230 drawState->setBlendFunc(kOne_BlendCoeff,
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000231 kZero_BlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000232 drawState->setFirstCoverageStage(GrDrawState::kNumStages);
233 drawState->setDrawFace(GrDrawState::kBoth_DrawFace);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000234}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000235}
236
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000237GrContext::TextureCacheEntry GrContext::findAndLockTexture(
238 TextureKey key,
239 int width,
240 int height,
241 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000242 uint32_t v[4];
243 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
244 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000245 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
246 GrResourceCache::kNested_LockType));
247}
248
bsalomon@google.comfb309512011-11-30 14:13:48 +0000249bool GrContext::isTextureInCache(TextureKey key,
250 int width,
251 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000252 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000253 uint32_t v[4];
254 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
255 GrResourceKey resourceKey(v);
256 return fTextureCache->hasKey(resourceKey);
257}
258
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000259GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000260 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000261 uint32_t v[4];
262 gen_stencil_key_values(sb, v);
263 GrResourceKey resourceKey(v);
264 return fTextureCache->createAndLock(resourceKey, sb);
265}
266
267GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
268 int sampleCnt) {
269 uint32_t v[4];
270 gen_stencil_key_values(width, height, sampleCnt, v);
271 GrResourceKey resourceKey(v);
272 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
273 GrResourceCache::kSingle_LockType);
274 if (NULL != entry) {
275 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
276 return sb;
277 } else {
278 return NULL;
279 }
280}
281
282void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000283 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000284 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000285}
286
287static void stretchImage(void* dst,
288 int dstW,
289 int dstH,
290 void* src,
291 int srcW,
292 int srcH,
293 int bpp) {
294 GrFixed dx = (srcW << 16) / dstW;
295 GrFixed dy = (srcH << 16) / dstH;
296
297 GrFixed y = dy >> 1;
298
299 int dstXLimit = dstW*bpp;
300 for (int j = 0; j < dstH; ++j) {
301 GrFixed x = dx >> 1;
302 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
303 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
304 for (int i = 0; i < dstXLimit; i += bpp) {
305 memcpy((uint8_t*) dstRow + i,
306 (uint8_t*) srcRow + (x>>16)*bpp,
307 bpp);
308 x += dx;
309 }
310 y += dy;
311 }
312}
313
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000314GrContext::TextureCacheEntry GrContext::createAndLockTexture(
315 TextureKey key,
316 const GrSamplerState* sampler,
317 const GrTextureDesc& desc,
318 void* srcData,
319 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000320 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000321
322#if GR_DUMP_TEXTURE_UPLOAD
323 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
324#endif
325
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000326 TextureCacheEntry entry;
327 uint32_t v[4];
328 bool special = gen_texture_key_values(fGpu, sampler, key,
329 desc.fWidth, desc.fHeight, false, v);
330 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000331
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000332 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000333 GrAssert(NULL != sampler);
334 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
335 desc.fWidth,
336 desc.fHeight,
337 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000338
339 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000340 clampEntry = this->createAndLockTexture(key, NULL, desc,
341 srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000342 GrAssert(NULL != clampEntry.texture());
343 if (NULL == clampEntry.texture()) {
344 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000345 }
346 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000347 GrTextureDesc rtDesc = desc;
348 rtDesc.fFlags = rtDesc.fFlags |
349 kRenderTarget_GrTextureFlagBit |
350 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000351 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
352 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000353
354 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
355
356 if (NULL != texture) {
357 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000358 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +0000359 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000360 drawState->setRenderTarget(texture->asRenderTarget());
361 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000362
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000363 GrSamplerState::Filter filter;
364 // if filtering is not desired then we want to ensure all
365 // texels in the resampled image are copies of texels from
366 // the original.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000367 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000368 filter = GrSamplerState::kNearest_Filter;
369 } else {
370 filter = GrSamplerState::kBilinear_Filter;
371 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000372 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
373 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000374
375 static const GrVertexLayout layout =
376 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
377 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
378
379 if (arg.succeeded()) {
380 GrPoint* verts = (GrPoint*) arg.vertices();
381 verts[0].setIRectFan(0, 0,
382 texture->width(),
383 texture->height(),
384 2*sizeof(GrPoint));
385 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
386 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
387 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000388 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000390 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 } else {
392 // TODO: Our CPU stretch doesn't filter. But we create separate
393 // stretched textures when the sampler state is either filtered or
394 // not. Either implement filtered stretch blit on CPU or just create
395 // one when FBO case fails.
396
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000397 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 // no longer need to clamp at min RT size.
399 rtDesc.fWidth = GrNextPow2(desc.fWidth);
400 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000401 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000402 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000403 rtDesc.fWidth *
404 rtDesc.fHeight);
405 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
406 srcData, desc.fWidth, desc.fHeight, bpp);
407
408 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
409
410 GrTexture* texture = fGpu->createTexture(rtDesc,
411 stretchedPixels.get(),
412 stretchedRowBytes);
413 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000417
418 } else {
419 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
420 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000422 }
423 }
424 return entry;
425}
426
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427namespace {
428inline void gen_scratch_tex_key_values(const GrGpu* gpu,
429 const GrTextureDesc& desc,
430 uint32_t v[4]) {
431 // Instead of a client-provided key of the texture contents
432 // we create a key of from the descriptor.
433 GrContext::TextureKey descKey = desc.fAALevel |
434 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000435 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000436 // this code path isn't friendly to tiling with NPOT restricitons
437 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000438 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
439 desc.fHeight, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000440}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000441}
442
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000443GrContext::TextureCacheEntry GrContext::lockScratchTexture(
444 const GrTextureDesc& inDesc,
445 ScratchTexMatch match) {
446
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000447 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000448 if (kExact_ScratchTexMatch != match) {
449 // bin by pow2 with a reasonable min
450 static const int MIN_SIZE = 256;
451 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
452 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
453 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000454
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000455 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000456 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
457
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000458 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000459 int origWidth = desc.fWidth;
460 int origHeight = desc.fHeight;
461 bool doubledW = false;
462 bool doubledH = false;
463
464 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000465 uint32_t v[4];
466 gen_scratch_tex_key_values(fGpu, desc, v);
467 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000468 entry = fTextureCache->findAndLock(key,
469 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000470 // if we miss, relax the fit of the flags...
471 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000472 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000473 break;
474 }
475 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
476 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
477 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
478 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
479 } else if (!doubledW) {
480 desc.fFlags = inDesc.fFlags;
481 desc.fWidth *= 2;
482 doubledW = true;
483 } else if (!doubledH) {
484 desc.fFlags = inDesc.fFlags;
485 desc.fWidth = origWidth;
486 desc.fHeight *= 2;
487 doubledH = true;
488 } else {
489 break;
490 }
491
492 } while (true);
493
494 if (NULL == entry) {
495 desc.fFlags = inDesc.fFlags;
496 desc.fWidth = origWidth;
497 desc.fHeight = origHeight;
498 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
499 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000500 uint32_t v[4];
501 gen_scratch_tex_key_values(fGpu, desc, v);
502 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000503 entry = fTextureCache->createAndLock(key, texture);
504 }
505 }
506
507 // If the caller gives us the same desc/sampler twice we don't want
508 // to return the same texture the second time (unless it was previously
509 // released). So we detach the entry from the cache and reattach at release.
510 if (NULL != entry) {
511 fTextureCache->detach(entry);
512 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000514}
515
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000516void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000517 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518 // If this is a scratch texture we detached it from the cache
519 // while it was locked (to avoid two callers simultaneously getting
520 // the same texture).
521 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
522 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000523 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000524 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000525 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000526}
527
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000528GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000529 void* srcData,
530 size_t rowBytes) {
531 return fGpu->createTexture(desc, srcData, rowBytes);
532}
533
534void GrContext::getTextureCacheLimits(int* maxTextures,
535 size_t* maxTextureBytes) const {
536 fTextureCache->getLimits(maxTextures, maxTextureBytes);
537}
538
539void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
540 fTextureCache->setLimits(maxTextures, maxTextureBytes);
541}
542
bsalomon@google.com91958362011-06-13 17:58:13 +0000543int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000544 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000545}
546
547int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000548 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000549}
550
551///////////////////////////////////////////////////////////////////////////////
552
bsalomon@google.come269f212011-11-07 13:29:52 +0000553GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
554 return fGpu->createPlatformTexture(desc);
555}
556
557GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
558 return fGpu->createPlatformRenderTarget(desc);
559}
560
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000561GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
562 // validate flags here so that GrGpu subclasses don't have to check
563 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
564 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000565 return NULL;
566 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000567 if (desc.fSampleCnt &&
568 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000569 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000570 }
571 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
572 desc.fSampleCnt &&
573 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
574 return NULL;
575 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000576 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577}
578
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000579///////////////////////////////////////////////////////////////////////////////
580
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000581bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000582 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000583 const GrDrawTarget::Caps& caps = fGpu->getCaps();
584 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000585 return false;
586 }
587
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
589
590 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000591 bool tiled = NULL != sampler &&
592 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
593 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000594 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000595 return false;
596 }
597 }
598 return true;
599}
600
601////////////////////////////////////////////////////////////////////////////////
602
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000603const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
604
bsalomon@google.com27847de2011-02-22 20:59:41 +0000605void GrContext::setClip(const GrClip& clip) {
606 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000607 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000608}
609
610void GrContext::setClip(const GrIRect& rect) {
611 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000612 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000613 fGpu->setClip(clip);
614}
615
616////////////////////////////////////////////////////////////////////////////////
617
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000618void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000619 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000620 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000621}
622
623void GrContext::drawPaint(const GrPaint& paint) {
624 // set rect to be big enough to fill the space, but not super-huge, so we
625 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000626 GrRect r;
627 r.setLTRB(0, 0,
628 GrIntToScalar(getRenderTarget()->width()),
629 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000630 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000631 SkTLazy<GrPaint> tmpPaint;
632 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000633 GrDrawState* drawState = fGpu->drawState();
634 GrAutoMatrix am;
635
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000636 // We attempt to map r by the inverse matrix and draw that. mapRect will
637 // map the four corners and bound them with a new rect. This will not
638 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000639 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000640 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000641 GrPrintf("Could not invert matrix");
642 return;
643 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000644 inverse.mapRect(&r);
645 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000646 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000647 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000648 GrPrintf("Could not invert matrix");
649 return;
650 }
651 tmpPaint.set(paint);
652 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
653 p = tmpPaint.get();
654 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000655 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000656 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000657 // by definition this fills the entire clip, no need for AA
658 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000659 if (!tmpPaint.isValid()) {
660 tmpPaint.set(paint);
661 p = tmpPaint.get();
662 }
663 GrAssert(p == tmpPaint.get());
664 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000665 }
666 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000667}
668
bsalomon@google.com205d4602011-04-25 12:43:45 +0000669////////////////////////////////////////////////////////////////////////////////
670
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000671namespace {
672inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
673 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
674}
675}
676
bsalomon@google.com91958362011-06-13 17:58:13 +0000677struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000678 enum Downsample {
bsalomon@google.com91958362011-06-13 17:58:13 +0000679 k4x4SinglePass_Downsample,
680 kFSAA_Downsample
681 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000682 int fTileSizeX;
683 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000684 int fTileCountX;
685 int fTileCountY;
686 int fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000687 GrAutoScratchTexture fOffscreen;
bsalomon@google.com91958362011-06-13 17:58:13 +0000688 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000689 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000690};
691
bsalomon@google.com471d4712011-08-23 15:45:25 +0000692bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000693 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000694#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000695 return false;
696#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000697 // Line primitves are always rasterized as 1 pixel wide.
698 // Super-sampling would make them too thin but MSAA would be OK.
699 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000700 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000701 return false;
702 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000703 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000704 return false;
705 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000706 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000707#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000708 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000709#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000710 return false;
711 }
712 return true;
713#endif
714}
715
bsalomon@google.com91958362011-06-13 17:58:13 +0000716bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000717 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000718 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000719 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000720 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000721
722 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000723
bsalomon@google.com46579e02012-01-11 18:51:15 +0000724 GrAssert(NULL == record->fOffscreen.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000725 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000726
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000727 int boundW = boundRect.width();
728 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000729
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000730 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000731
732 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
733 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
734
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000735 if (requireStencil) {
736 desc.fFlags = kRenderTarget_GrTextureFlagBit;
737 } else {
738 desc.fFlags = kRenderTarget_GrTextureFlagBit |
739 kNoStencil_GrTextureFlagBit;
740 }
741
bsalomon@google.comc4364992011-11-07 15:54:49 +0000742 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000743
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000744 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000745 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000746 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000747 desc.fAALevel = kMed_GrAALevel;
748 } else {
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000749 record->fDownsample = OffscreenRecord::k4x4SinglePass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000750 record->fScale = OFFSCREEN_SSAA_SCALE;
751 // both downsample paths assume this
752 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000753 desc.fAALevel = kNone_GrAALevel;
754 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000755
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000756 desc.fWidth *= record->fScale;
757 desc.fHeight *= record->fScale;
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000758 record->fOffscreen.set(this, desc);
759 if (NULL == record->fOffscreen.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000760 return false;
761 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000762 // the approximate lookup might have given us some slop space, might as well
763 // use it when computing the tiles size.
764 // these are scale values, will adjust after considering
765 // the possible second offscreen.
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000766 record->fTileSizeX = record->fOffscreen.texture()->width();
767 record->fTileSizeY = record->fOffscreen.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000769 record->fTileSizeX /= record->fScale;
770 record->fTileSizeY /= record->fScale;
771
772 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
773 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
774
tomhudson@google.com237a4612011-07-19 15:44:00 +0000775 record->fClip = target->getClip();
776
bsalomon@google.com91958362011-06-13 17:58:13 +0000777 target->saveCurrentDrawState(&record->fSavedState);
778 return true;
779}
780
781void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
782 const GrIRect& boundRect,
783 int tileX, int tileY,
784 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000785
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000786 GrRenderTarget* offRT = record->fOffscreen.texture()->asRenderTarget();
787 GrAssert(NULL != offRT);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000788
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000789 GrPaint tempPaint;
790 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000791 this->setPaint(tempPaint, target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000792 GrDrawState* drawState = target->drawState();
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000793 drawState->setRenderTarget(offRT);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000794#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com337af172012-01-11 16:00:42 +0000795 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000796#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000797
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000798 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000799 int left = boundRect.fLeft + tileX * record->fTileSizeX;
800 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000801 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000802 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000803 GrMatrix scaleM;
804 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000805 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000806
bsalomon@google.com91958362011-06-13 17:58:13 +0000807 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000808 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000809 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000811 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
812 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000813 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000814#if 0
815 // visualize tile boundaries by setting edges of offscreen to white
816 // and interior to tranparent. black.
817 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000818
bsalomon@google.com91958362011-06-13 17:58:13 +0000819 static const int gOffset = 2;
820 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
821 record->fScale * w - gOffset,
822 record->fScale * h - gOffset);
823 target->clear(&clear2, 0x0);
824#else
825 target->clear(&clear, 0x0);
826#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000827}
828
bsalomon@google.com91958362011-06-13 17:58:13 +0000829void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000830 const GrPaint& paint,
831 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000832 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000833 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000834 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com46579e02012-01-11 18:51:15 +0000835 GrAssert(NULL != record->fOffscreen.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000836 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000837 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000838 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
839 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000840 tileRect.fRight = (tileX == record->fTileCountX-1) ?
841 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000842 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000843 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
844 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000845 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000846
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000847 GrSamplerState::Filter filter;
848 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
849 filter = GrSamplerState::k4x4Downsample_Filter;
850 } else {
851 filter = GrSamplerState::kBilinear_Filter;
852 }
853
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000854 GrTexture* src = record->fOffscreen.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000855 int scale;
856
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000857 enum {
858 kOffscreenStage = GrPaint::kTotalStages,
859 };
860
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000861 GrDrawState* drawState = target->drawState();
862
bsalomon@google.comdafde9e2012-01-11 18:45:39 +0000863 if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000865 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000866 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000867 } else {
868 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
869 record->fDownsample);
870 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871 }
872
bsalomon@google.com91958362011-06-13 17:58:13 +0000873 // setup for draw back to main RT, we use the original
874 // draw state setup by the caller plus an additional coverage
875 // stage to handle the AA resolve. Also, we use an identity
876 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000877 int stageMask = paint.getActiveStageMask();
878
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000879 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000880 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000881
882 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000883 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000884 if (drawState->getViewInverse(&invVM)) {
885 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000886 }
887 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000888 // This is important when tiling, otherwise second tile's
889 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000890 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000891
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000892 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000893 GrSamplerState* sampler = drawState->sampler(kOffscreenStage);
894 sampler->reset(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.comaa814fe2011-12-12 18:45:07 +0000895 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(),
896 scale * GR_Scalar1 / src->height());
897 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft),
898 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000899
reed@google.com20efde72011-05-09 17:00:02 +0000900 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000901 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000902 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000903 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000904}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000905
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000906void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
907 GrPathRenderer* pr,
908 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000909 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000910}
911
912////////////////////////////////////////////////////////////////////////////////
913
bsalomon@google.com27847de2011-02-22 20:59:41 +0000914/* create a triangle strip that strokes the specified triangle. There are 8
915 unique vertices, but we repreat the last 2 to close up. Alternatively we
916 could use an indices array, and then only send 8 verts, but not sure that
917 would be faster.
918 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000919static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000920 GrScalar width) {
921 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000922 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000923
924 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
925 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
926 verts[2].set(rect.fRight - rad, rect.fTop + rad);
927 verts[3].set(rect.fRight + rad, rect.fTop - rad);
928 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
929 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
930 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
931 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
932 verts[8] = verts[0];
933 verts[9] = verts[1];
934}
935
bsalomon@google.com205d4602011-04-25 12:43:45 +0000936static void setInsetFan(GrPoint* pts, size_t stride,
937 const GrRect& r, GrScalar dx, GrScalar dy) {
938 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
939}
940
941static const uint16_t gFillAARectIdx[] = {
942 0, 1, 5, 5, 4, 0,
943 1, 2, 6, 6, 5, 1,
944 2, 3, 7, 7, 6, 2,
945 3, 0, 4, 4, 7, 3,
946 4, 5, 6, 6, 7, 4,
947};
948
949int GrContext::aaFillRectIndexCount() const {
950 return GR_ARRAY_COUNT(gFillAARectIdx);
951}
952
953GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
954 if (NULL == fAAFillRectIndexBuffer) {
955 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
956 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000957 if (NULL != fAAFillRectIndexBuffer) {
958 #if GR_DEBUG
959 bool updated =
960 #endif
961 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
962 sizeof(gFillAARectIdx));
963 GR_DEBUGASSERT(updated);
964 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000965 }
966 return fAAFillRectIndexBuffer;
967}
968
969static const uint16_t gStrokeAARectIdx[] = {
970 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
971 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
972 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
973 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
974
975 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
976 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
977 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
978 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
979
980 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
981 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
982 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
983 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
984};
985
986int GrContext::aaStrokeRectIndexCount() const {
987 return GR_ARRAY_COUNT(gStrokeAARectIdx);
988}
989
990GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
991 if (NULL == fAAStrokeRectIndexBuffer) {
992 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
993 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000994 if (NULL != fAAStrokeRectIndexBuffer) {
995 #if GR_DEBUG
996 bool updated =
997 #endif
998 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
999 sizeof(gStrokeAARectIdx));
1000 GR_DEBUGASSERT(updated);
1001 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001002 }
1003 return fAAStrokeRectIndexBuffer;
1004}
1005
bsalomon@google.coma3108262011-10-10 14:08:47 +00001006static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1007 bool useCoverage) {
1008 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001009 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001010 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001011 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1012 }
1013 }
1014 if (useCoverage) {
1015 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1016 } else {
1017 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1018 }
1019 return layout;
1020}
1021
bsalomon@google.com205d4602011-04-25 12:43:45 +00001022void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001023 const GrRect& devRect,
1024 bool useVertexCoverage) {
1025 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001026
1027 size_t vsize = GrDrawTarget::VertexSize(layout);
1028
1029 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001030 if (!geo.succeeded()) {
1031 GrPrintf("Failed to get space for vertices!\n");
1032 return;
1033 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001034 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1035 if (NULL == indexBuffer) {
1036 GrPrintf("Failed to create index buffer!\n");
1037 return;
1038 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001039
1040 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1041
1042 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1043 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1044
1045 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1046 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1047
1048 verts += sizeof(GrPoint);
1049 for (int i = 0; i < 4; ++i) {
1050 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1051 }
1052
bsalomon@google.coma3108262011-10-10 14:08:47 +00001053 GrColor innerColor;
1054 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001055 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001056 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001057 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001058 }
1059
bsalomon@google.com205d4602011-04-25 12:43:45 +00001060 verts += 4 * vsize;
1061 for (int i = 0; i < 4; ++i) {
1062 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1063 }
1064
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001065 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001066
1067 target->drawIndexed(kTriangles_PrimitiveType, 0,
1068 0, 8, this->aaFillRectIndexCount());
1069}
1070
bsalomon@google.coma3108262011-10-10 14:08:47 +00001071void GrContext::strokeAARect(GrDrawTarget* target,
1072 const GrRect& devRect,
1073 const GrVec& devStrokeSize,
1074 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001075 const GrScalar& dx = devStrokeSize.fX;
1076 const GrScalar& dy = devStrokeSize.fY;
1077 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1078 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1079
bsalomon@google.com205d4602011-04-25 12:43:45 +00001080 GrScalar spare;
1081 {
1082 GrScalar w = devRect.width() - dx;
1083 GrScalar h = devRect.height() - dy;
1084 spare = GrMin(w, h);
1085 }
1086
1087 if (spare <= 0) {
1088 GrRect r(devRect);
1089 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001090 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001091 return;
1092 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001093 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001094 size_t vsize = GrDrawTarget::VertexSize(layout);
1095
1096 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001097 if (!geo.succeeded()) {
1098 GrPrintf("Failed to get space for vertices!\n");
1099 return;
1100 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001101 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1102 if (NULL == indexBuffer) {
1103 GrPrintf("Failed to create index buffer!\n");
1104 return;
1105 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001106
1107 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1108
1109 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1110 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1111 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1112 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1113
1114 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1115 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1116 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1117 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1118
1119 verts += sizeof(GrPoint);
1120 for (int i = 0; i < 4; ++i) {
1121 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1122 }
1123
bsalomon@google.coma3108262011-10-10 14:08:47 +00001124 GrColor innerColor;
1125 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001126 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001127 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001128 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001129 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001130 verts += 4 * vsize;
1131 for (int i = 0; i < 8; ++i) {
1132 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1133 }
1134
1135 verts += 8 * vsize;
1136 for (int i = 0; i < 8; ++i) {
1137 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1138 }
1139
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001140 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001141 target->drawIndexed(kTriangles_PrimitiveType,
1142 0, 0, 16, aaStrokeRectIndexCount());
1143}
1144
reed@google.com20efde72011-05-09 17:00:02 +00001145/**
1146 * Returns true if the rects edges are integer-aligned.
1147 */
1148static bool isIRect(const GrRect& r) {
1149 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1150 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1151}
1152
bsalomon@google.com205d4602011-04-25 12:43:45 +00001153static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001154 const GrRect& rect,
1155 GrScalar width,
1156 const GrMatrix* matrix,
1157 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001158 GrRect* devRect,
1159 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001160 // we use a simple coverage ramp to do aa on axis-aligned rects
1161 // we check if the rect will be axis-aligned, and the rect won't land on
1162 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001163
bsalomon@google.coma3108262011-10-10 14:08:47 +00001164 // we are keeping around the "tweak the alpha" trick because
1165 // it is our only hope for the fixed-pipe implementation.
1166 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001167 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001168 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001169 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001170 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001171#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001172 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001173#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001174 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +00001175 } else {
1176 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001177 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001178 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001179 const GrDrawState& drawState = target->getDrawState();
1180 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001181 return false;
1182 }
1183
bsalomon@google.com471d4712011-08-23 15:45:25 +00001184 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001185 return false;
1186 }
1187
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001188 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001189 return false;
1190 }
1191
1192 if (NULL != matrix &&
1193 !matrix->preservesAxisAlignment()) {
1194 return false;
1195 }
1196
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001197 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001198 if (NULL != matrix) {
1199 combinedMatrix->preConcat(*matrix);
1200 GrAssert(combinedMatrix->preservesAxisAlignment());
1201 }
1202
1203 combinedMatrix->mapRect(devRect, rect);
1204 devRect->sort();
1205
1206 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001207 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001208 } else {
1209 return true;
1210 }
1211}
1212
bsalomon@google.com27847de2011-02-22 20:59:41 +00001213void GrContext::drawRect(const GrPaint& paint,
1214 const GrRect& rect,
1215 GrScalar width,
1216 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001217 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001218
1219 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001220 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001221
bsalomon@google.com205d4602011-04-25 12:43:45 +00001222 GrRect devRect = rect;
1223 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001224 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001225 bool needAA = paint.fAntiAlias &&
1226 !this->getRenderTarget()->isMultisampled();
1227 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1228 &combinedMatrix, &devRect,
1229 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001230
1231 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001232 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001233 if (width >= 0) {
1234 GrVec strokeSize;;
1235 if (width > 0) {
1236 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001237 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001238 strokeSize.setAbs(strokeSize);
1239 } else {
1240 strokeSize.set(GR_Scalar1, GR_Scalar1);
1241 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001242 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001243 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001244 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001245 }
1246 return;
1247 }
1248
bsalomon@google.com27847de2011-02-22 20:59:41 +00001249 if (width >= 0) {
1250 // TODO: consider making static vertex buffers for these cases.
1251 // Hairline could be done by just adding closing vertex to
1252 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001253 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1254
bsalomon@google.com27847de2011-02-22 20:59:41 +00001255 static const int worstCaseVertCount = 10;
1256 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1257
1258 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001259 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001260 return;
1261 }
1262
1263 GrPrimitiveType primType;
1264 int vertCount;
1265 GrPoint* vertex = geo.positions();
1266
1267 if (width > 0) {
1268 vertCount = 10;
1269 primType = kTriangleStrip_PrimitiveType;
1270 setStrokeRectStrip(vertex, rect, width);
1271 } else {
1272 // hairline
1273 vertCount = 5;
1274 primType = kLineStrip_PrimitiveType;
1275 vertex[0].set(rect.fLeft, rect.fTop);
1276 vertex[1].set(rect.fRight, rect.fTop);
1277 vertex[2].set(rect.fRight, rect.fBottom);
1278 vertex[3].set(rect.fLeft, rect.fBottom);
1279 vertex[4].set(rect.fLeft, rect.fTop);
1280 }
1281
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001282 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001283 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001284 GrDrawState* drawState = target->drawState();
1285 avmr.set(drawState);
1286 drawState->preConcatViewMatrix(*matrix);
1287 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001288 }
1289
1290 target->drawNonIndexed(primType, 0, vertCount);
1291 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001292#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001293 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001294 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1295 if (NULL == sqVB) {
1296 GrPrintf("Failed to create static rect vb.\n");
1297 return;
1298 }
1299 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001300 GrDrawState* drawState = target->drawState();
1301 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001302 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001303 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001304 0, rect.height(), rect.fTop,
1305 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001306
1307 if (NULL != matrix) {
1308 m.postConcat(*matrix);
1309 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001310 drawState->preConcatViewMatrix(m);
1311 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001312
bsalomon@google.com27847de2011-02-22 20:59:41 +00001313 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001314#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001315 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001316#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317 }
1318}
1319
1320void GrContext::drawRectToRect(const GrPaint& paint,
1321 const GrRect& dstRect,
1322 const GrRect& srcRect,
1323 const GrMatrix* dstMatrix,
1324 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001325 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001327 // srcRect refers to paint's first texture
1328 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001329 drawRect(paint, dstRect, -1, dstMatrix);
1330 return;
1331 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001332
bsalomon@google.com27847de2011-02-22 20:59:41 +00001333 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1334
1335#if GR_STATIC_RECT_VB
1336 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001337 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001338 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001339 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001340
1341 GrMatrix m;
1342
1343 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1344 0, dstRect.height(), dstRect.fTop,
1345 0, 0, GrMatrix::I()[8]);
1346 if (NULL != dstMatrix) {
1347 m.postConcat(*dstMatrix);
1348 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001349 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001350
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001351 // srcRect refers to first stage
1352 int otherStageMask = paint.getActiveStageMask() &
1353 (~(1 << GrPaint::kFirstTextureStage));
1354 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001355 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001356 }
1357
bsalomon@google.com27847de2011-02-22 20:59:41 +00001358 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1359 0, srcRect.height(), srcRect.fTop,
1360 0, 0, GrMatrix::I()[8]);
1361 if (NULL != srcMatrix) {
1362 m.postConcat(*srcMatrix);
1363 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001364 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001365
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001366 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1367 if (NULL == sqVB) {
1368 GrPrintf("Failed to create static rect vb.\n");
1369 return;
1370 }
1371 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1373#else
1374
1375 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001376#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001378#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1380#endif
1381
tomhudson@google.com93813632011-10-27 20:21:16 +00001382 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1383 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001384 srcRects[0] = &srcRect;
1385 srcMatrices[0] = srcMatrix;
1386
1387 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1388#endif
1389}
1390
1391void GrContext::drawVertices(const GrPaint& paint,
1392 GrPrimitiveType primitiveType,
1393 int vertexCount,
1394 const GrPoint positions[],
1395 const GrPoint texCoords[],
1396 const GrColor colors[],
1397 const uint16_t indices[],
1398 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001399 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001400
1401 GrDrawTarget::AutoReleaseGeometry geo;
1402
1403 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1404
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001405 bool hasTexCoords[GrPaint::kTotalStages] = {
1406 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1407 0 // remaining stages use positions
1408 };
1409
1410 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001411
1412 if (NULL != colors) {
1413 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001414 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001415 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416
1417 if (sizeof(GrPoint) != vertexSize) {
1418 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001419 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420 return;
1421 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001422 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001424 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1425 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001426 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001427 NULL,
1428 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001429 void* curVertex = geo.vertices();
1430
1431 for (int i = 0; i < vertexCount; ++i) {
1432 *((GrPoint*)curVertex) = positions[i];
1433
1434 if (texOffsets[0] > 0) {
1435 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1436 }
1437 if (colorOffset > 0) {
1438 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1439 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001440 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441 }
1442 } else {
1443 target->setVertexSourceToArray(layout, positions, vertexCount);
1444 }
1445
bsalomon@google.com91958362011-06-13 17:58:13 +00001446 // we don't currently apply offscreen AA to this path. Need improved
1447 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001448
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001449 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001450 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001451 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001452 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001453 target->drawNonIndexed(primitiveType, 0, vertexCount);
1454 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001455}
1456
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001457///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001458#include "SkDraw.h"
1459#include "SkRasterClip.h"
1460
1461namespace {
1462
1463SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1464 switch (fill) {
1465 case kWinding_PathFill:
1466 return SkPath::kWinding_FillType;
1467 case kEvenOdd_PathFill:
1468 return SkPath::kEvenOdd_FillType;
1469 case kInverseWinding_PathFill:
1470 return SkPath::kInverseWinding_FillType;
1471 case kInverseEvenOdd_PathFill:
1472 return SkPath::kInverseEvenOdd_FillType;
1473 default:
1474 GrCrash("Unexpected fill.");
1475 return SkPath::kWinding_FillType;
1476 }
1477}
1478
1479// gets device coord bounds of path (not considering the fill) and clip. The
1480// path bounds will be a subset of the clip bounds. returns false if path bounds
1481// would be empty.
1482bool get_path_and_clip_bounds(const GrDrawTarget* target,
1483 const GrPath& path,
1484 const GrVec* translate,
1485 GrIRect* pathBounds,
1486 GrIRect* clipBounds) {
1487 // compute bounds as intersection of rt size, clip, and path
1488 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1489 if (NULL == rt) {
1490 return false;
1491 }
1492 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1493 const GrClip& clip = target->getClip();
1494 if (clip.hasConservativeBounds()) {
1495 clip.getConservativeBounds().roundOut(clipBounds);
1496 if (!pathBounds->intersect(*clipBounds)) {
1497 return false;
1498 }
1499 } else {
1500 // pathBounds is currently the rt extent, set clip bounds to that rect.
1501 *clipBounds = *pathBounds;
1502 }
1503 GrRect pathSBounds = path.getBounds();
1504 if (!pathSBounds.isEmpty()) {
1505 if (NULL != translate) {
1506 pathSBounds.offset(*translate);
1507 }
1508 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1509 pathSBounds);
1510 GrIRect pathIBounds;
1511 pathSBounds.roundOut(&pathIBounds);
1512 if (!pathBounds->intersect(pathIBounds)) {
1513 return false;
1514 }
1515 } else {
1516 return false;
1517 }
1518 return true;
1519}
1520
1521/**
1522 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1523 * scratch texture.
1524 */
1525
1526bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1527 const GrIRect& pathDevBounds,
1528 GrPathFill fill,
1529 GrContext* context,
1530 const GrPoint* translate,
1531 GrAutoScratchTexture* tex) {
1532 SkPaint paint;
1533 SkPath tmpPath;
1534 const SkPath* pathToDraw = &clientPath;
1535 if (kHairLine_PathFill == fill) {
1536 paint.setStyle(SkPaint::kStroke_Style);
1537 paint.setStrokeWidth(SK_Scalar1);
1538 } else {
1539 paint.setStyle(SkPaint::kFill_Style);
1540 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1541 if (skfill != pathToDraw->getFillType()) {
1542 tmpPath = *pathToDraw;
1543 tmpPath.setFillType(skfill);
1544 pathToDraw = &tmpPath;
1545 }
1546 }
1547 paint.setAntiAlias(true);
1548 paint.setColor(SK_ColorWHITE);
1549
1550 GrMatrix matrix = context->getMatrix();
1551 if (NULL != translate) {
1552 matrix.postTranslate(translate->fX, translate->fY);
1553 }
1554
1555 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1556 -pathDevBounds.fTop * SK_Scalar1);
1557 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1558 pathDevBounds.height());
1559
1560 SkBitmap bm;
1561 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1562 if (!bm.allocPixels()) {
1563 return false;
1564 }
1565 sk_bzero(bm.getPixels(), bm.getSafeSize());
1566
1567 SkDraw draw;
1568 sk_bzero(&draw, sizeof(draw));
1569 SkRasterClip rc(bounds);
1570 draw.fRC = &rc;
1571 draw.fClip = &rc.bwRgn();
1572 draw.fMatrix = &matrix;
1573 draw.fBitmap = &bm;
1574 draw.drawPath(*pathToDraw, paint);
1575
1576 const GrTextureDesc desc = {
1577 kNone_GrTextureFlags,
1578 kNone_GrAALevel,
1579 bounds.fRight,
1580 bounds.fBottom,
1581 kAlpha_8_GrPixelConfig
1582 };
1583
1584 tex->set(context, desc);
1585 GrTexture* texture = tex->texture();
1586
1587 if (NULL == texture) {
1588 return false;
1589 }
1590 SkAutoLockPixels alp(bm);
1591 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1592 bm.getPixels(), bm.rowBytes());
1593 return true;
1594}
1595
1596void draw_around_inv_path(GrDrawTarget* target,
1597 GrDrawState::StageMask stageMask,
1598 const GrIRect& clipBounds,
1599 const GrIRect& pathBounds) {
1600 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1601 GrRect rect;
1602 if (clipBounds.fTop < pathBounds.fTop) {
1603 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1604 clipBounds.fRight, pathBounds.fTop);
1605 target->drawSimpleRect(rect, NULL, stageMask);
1606 }
1607 if (clipBounds.fLeft < pathBounds.fLeft) {
1608 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1609 pathBounds.fLeft, pathBounds.fBottom);
1610 target->drawSimpleRect(rect, NULL, stageMask);
1611 }
1612 if (clipBounds.fRight > pathBounds.fRight) {
1613 rect.iset(pathBounds.fRight, pathBounds.fTop,
1614 clipBounds.fRight, pathBounds.fBottom);
1615 target->drawSimpleRect(rect, NULL, stageMask);
1616 }
1617 if (clipBounds.fBottom > pathBounds.fBottom) {
1618 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1619 clipBounds.fRight, clipBounds.fBottom);
1620 target->drawSimpleRect(rect, NULL, stageMask);
1621 }
1622}
1623
1624}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001625
reed@google.com07f3ee12011-05-16 17:21:57 +00001626void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1627 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001628
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001629 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001630 if (GrIsFillInverted(fill)) {
1631 this->drawPaint(paint);
1632 }
1633 return;
1634 }
1635
bsalomon@google.com27847de2011-02-22 20:59:41 +00001636 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001637 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001638
bsalomon@google.com289533a2011-10-27 12:34:25 +00001639 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1640
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001641 // An Assumption here is that path renderer would use some form of tweaking
1642 // the src color (either the input alpha or in the frag shader) to implement
1643 // aa. If we have some future driver-mojo path AA that can do the right
1644 // thing WRT to the blend then we'll need some query on the PR.
1645 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001646#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001647 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001648#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001649 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001650 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001651
1652 bool doOSAA = false;
1653 GrPathRenderer* pr = NULL;
1654 if (prAA) {
1655 pr = this->getPathRenderer(path, fill, true);
1656 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001657 GrAutoScratchTexture ast;
1658 GrIRect pathBounds, clipBounds;
1659 if (!get_path_and_clip_bounds(target, path, translate,
1660 &pathBounds, &clipBounds)) {
1661 return;
1662 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001663 prAA = false;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001664 if (this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
1665 pr = this->getPathRenderer(path, fill, false);
1666 doOSAA = true;
1667 }
1668 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1669 fill, this,
1670 translate, &ast)) {
1671 GrTexture* texture = ast.texture();
1672 GrAssert(NULL != texture);
1673 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1674 enum {
1675 kPathMaskStage = GrPaint::kTotalStages,
1676 };
1677 target->drawState()->setTexture(kPathMaskStage, texture);
1678 target->drawState()->sampler(kPathMaskStage)->reset();
1679 GrScalar w = GrIntToScalar(pathBounds.width());
1680 GrScalar h = GrIntToScalar(pathBounds.height());
1681 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1682 h / texture->height());
1683 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1684 srcRects[kPathMaskStage] = &maskRect;
1685 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001686 GrRect dstRect = GrRect::MakeLTRB(
1687 SK_Scalar1* pathBounds.fLeft,
1688 SK_Scalar1* pathBounds.fTop,
1689 SK_Scalar1* pathBounds.fRight,
1690 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001691 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1692 target->drawState()->setTexture(kPathMaskStage, NULL);
1693 if (GrIsFillInverted(fill)) {
1694 draw_around_inv_path(target, stageMask,
1695 clipBounds, pathBounds);
1696 }
1697 return;
1698 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001699 }
1700 } else {
1701 pr = this->getPathRenderer(path, fill, false);
1702 }
1703
bsalomon@google.com30085192011-08-19 15:42:31 +00001704 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001705#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001706 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001707#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001708 return;
1709 }
1710
bsalomon@google.com289533a2011-10-27 12:34:25 +00001711 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001712
bsalomon@google.com289533a2011-10-27 12:34:25 +00001713 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001714 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001715 GrIRect pathBounds;
1716 GrIRect clipBounds;
1717 if (!get_path_and_clip_bounds(target, path, translate,
1718 &pathBounds, &clipBounds)) {
1719 return;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001720 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001721 OffscreenRecord record;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001722 if (this->prepareForOffscreenAA(target, needsStencil, pathBounds,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001723 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001724 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1725 for (int ty = 0; ty < record.fTileCountY; ++ty) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001726 this->setupOffscreenAAPass1(target, pathBounds,
1727 tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001728 pr->drawPath(0);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001729 this->doOffscreenAAPass2(target, paint, pathBounds,
1730 tx, ty, &record);
bsalomon@google.com91958362011-06-13 17:58:13 +00001731 }
1732 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001733 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001734 if (GrIsFillInverted(fill)) {
1735 draw_around_inv_path(target, stageMask, clipBounds, pathBounds);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001736 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001737 return;
1738 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001739 }
1740 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001741}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001742
bsalomon@google.com27847de2011-02-22 20:59:41 +00001743////////////////////////////////////////////////////////////////////////////////
1744
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001745void GrContext::flush(int flagsBitfield) {
1746 if (kDiscard_FlushBit & flagsBitfield) {
1747 fDrawBuffer->reset();
1748 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001749 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001750 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001751 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001752 fGpu->forceRenderTargetFlush();
1753 }
1754}
1755
1756void GrContext::flushText() {
1757 if (kText_DrawCategory == fLastDrawCategory) {
1758 flushDrawBuffer();
1759 }
1760}
1761
1762void GrContext::flushDrawBuffer() {
1763#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001764 if (fDrawBuffer) {
1765 fDrawBuffer->playback(fGpu);
1766 fDrawBuffer->reset();
1767 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001768#endif
1769}
1770
bsalomon@google.com6f379512011-11-16 20:36:03 +00001771void GrContext::internalWriteTexturePixels(GrTexture* texture,
1772 int left, int top,
1773 int width, int height,
1774 GrPixelConfig config,
1775 const void* buffer,
1776 size_t rowBytes,
1777 uint32_t flags) {
1778 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001779 ASSERT_OWNED_RESOURCE(texture);
1780
bsalomon@google.com6f379512011-11-16 20:36:03 +00001781 if (!(kDontFlush_PixelOpsFlag & flags)) {
1782 this->flush();
1783 }
1784 // TODO: use scratch texture to perform conversion
1785 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1786 GrPixelConfigIsUnpremultiplied(config)) {
1787 return;
1788 }
1789
1790 fGpu->writeTexturePixels(texture, left, top, width, height,
1791 config, buffer, rowBytes);
1792}
1793
1794bool GrContext::internalReadTexturePixels(GrTexture* texture,
1795 int left, int top,
1796 int width, int height,
1797 GrPixelConfig config,
1798 void* buffer,
1799 size_t rowBytes,
1800 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001801 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001802 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001803
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001804 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001805 GrRenderTarget* target = texture->asRenderTarget();
1806 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001807 return this->internalReadRenderTargetPixels(target,
1808 left, top, width, height,
1809 config, buffer, rowBytes,
1810 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001811 } else {
1812 return false;
1813 }
1814}
1815
bsalomon@google.com6f379512011-11-16 20:36:03 +00001816bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1817 int left, int top,
1818 int width, int height,
1819 GrPixelConfig config,
1820 void* buffer,
1821 size_t rowBytes,
1822 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001823 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001824 ASSERT_OWNED_RESOURCE(target);
1825
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001826 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001827 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001828 if (NULL == target) {
1829 return false;
1830 }
1831 }
1832
1833 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1834 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1835 // not supported at this time.
1836 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1837 !GrPixelConfigIsUnpremultiplied(config)) {
1838 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001839 }
1840
bsalomon@google.com6f379512011-11-16 20:36:03 +00001841 if (!(kDontFlush_PixelOpsFlag & flags)) {
1842 this->flush();
1843 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001844
1845 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001846 bool swapRAndB = NULL != src &&
1847 fGpu->preferredReadPixelsConfig(config) ==
1848 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001849
1850 bool flipY = NULL != src &&
1851 fGpu->readPixelsWillPayForYFlip(target, left, top,
1852 width, height, config,
1853 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001854 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1855 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001856
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001857 if (NULL == src && alphaConversion) {
1858 // we should fallback to cpu conversion here. This could happen when
1859 // we were given an external render target by the client that is not
1860 // also a texture (e.g. FBO 0 in GL)
1861 return false;
1862 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001863 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001864 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001865 if (flipY || swapRAndB || alphaConversion) {
1866 GrAssert(NULL != src);
1867 if (swapRAndB) {
1868 config = GrPixelConfigSwapRAndB(config);
1869 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001870 }
1871 // Make the scratch a render target because we don't have a robust
1872 // readTexturePixels as of yet (it calls this function).
1873 const GrTextureDesc desc = {
1874 kRenderTarget_GrTextureFlagBit,
1875 kNone_GrAALevel,
1876 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001877 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001878 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001879
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001880 // When a full readback is faster than a partial we could always make
1881 // the scratch exactly match the passed rect. However, if we see many
1882 // different size rectangles we will trash our texture cache and pay the
1883 // cost of creating and destroying many textures. So, we only request
1884 // an exact match when the caller is reading an entire RT.
1885 ScratchTexMatch match = kApprox_ScratchTexMatch;
1886 if (0 == left &&
1887 0 == top &&
1888 target->width() == width &&
1889 target->height() == height &&
1890 fGpu->fullReadPixelsIsFasterThanPartial()) {
1891 match = kExact_ScratchTexMatch;
1892 }
1893 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001894 GrTexture* texture = ast.texture();
1895 if (!texture) {
1896 return false;
1897 }
1898 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001899 GrAssert(NULL != target);
1900
1901 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001902 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001903 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001904 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001905
bsalomon@google.comc4364992011-11-07 15:54:49 +00001906 GrMatrix matrix;
1907 if (flipY) {
1908 matrix.setTranslate(SK_Scalar1 * left,
1909 SK_Scalar1 * (top + height));
1910 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1911 } else {
1912 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1913 }
1914 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001915 drawState->sampler(0)->reset(matrix);
1916 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001917 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001918 GrRect rect;
1919 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1920 fGpu->drawSimpleRect(rect, NULL, 0x1);
1921 left = 0;
1922 top = 0;
1923 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001924 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001925 left, top, width, height,
1926 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001927}
1928
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001929void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1930 if (NULL == src || NULL == dst) {
1931 return;
1932 }
1933 ASSERT_OWNED_RESOURCE(src);
1934
1935 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001936 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001937 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001938 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001939 GrMatrix sampleM;
1940 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001941 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001942 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001943 SkRect rect = SkRect::MakeXYWH(0, 0,
1944 SK_Scalar1 * src->width(),
1945 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001946 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1947}
1948
bsalomon@google.com6f379512011-11-16 20:36:03 +00001949void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1950 int left, int top,
1951 int width, int height,
1952 GrPixelConfig config,
1953 const void* buffer,
1954 size_t rowBytes,
1955 uint32_t flags) {
1956 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001957 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001958
1959 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001960 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001961 if (NULL == target) {
1962 return;
1963 }
1964 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001965
1966 // TODO: when underlying api has a direct way to do this we should use it
1967 // (e.g. glDrawPixels on desktop GL).
1968
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001969 // If the RT is also a texture and we don't have to do PM/UPM conversion
1970 // then take the texture path, which we expect to be at least as fast or
1971 // faster since it doesn't use an intermediate texture as we do below.
1972
1973#if !GR_MAC_BUILD
1974 // At least some drivers on the Mac get confused when glTexImage2D is called
1975 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1976 // determine what OS versions and/or HW is affected.
1977 if (NULL != target->asTexture() &&
1978 GrPixelConfigIsUnpremultiplied(target->config()) ==
1979 GrPixelConfigIsUnpremultiplied(config)) {
1980
1981 this->internalWriteTexturePixels(target->asTexture(),
1982 left, top, width, height,
1983 config, buffer, rowBytes, flags);
1984 return;
1985 }
1986#endif
1987
1988 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1989 GrPixelConfigSwapRAndB(config);
1990 if (swapRAndB) {
1991 config = GrPixelConfigSwapRAndB(config);
1992 }
1993
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001994 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001995 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001996 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001997 GrAutoScratchTexture ast(this, desc);
1998 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001999 if (NULL == texture) {
2000 return;
2001 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00002002 this->internalWriteTexturePixels(texture, 0, 0, width, height,
2003 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002004
bsalomon@google.com27847de2011-02-22 20:59:41 +00002005 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002006 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002007 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002008
2009 GrMatrix matrix;
2010 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002011 drawState->setViewMatrix(matrix);
2012 drawState->setRenderTarget(target);
2013 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002014
bsalomon@google.com5c638652011-07-18 19:31:59 +00002015 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002016 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2017 GrSamplerState::kNearest_Filter,
2018 matrix);
2019 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002020
2021 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
2022 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002023 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00002024 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
2025 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002026 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00002027 return;
2028 }
2029 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
2030 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
2031}
2032////////////////////////////////////////////////////////////////////////////////
2033
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002034void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002035 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002036
2037 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
2038 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002039 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002040 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002041 if (paint.getTexture(i)) {
2042 *drawState->sampler(s) = paint.getTextureSampler(i);
2043 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002044 }
2045
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002046 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002047
2048 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
2049 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002050 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002051 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002052 if (paint.getMask(i)) {
2053 *drawState->sampler(s) = paint.getMaskSampler(i);
2054 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002055 }
2056
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002057 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002058
2059 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002060 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002061 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002062 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002063 }
2064 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002065 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002066 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002067 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002068 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002069 if (paint.fColorMatrixEnabled) {
2070 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
2071 } else {
2072 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
2073 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002074 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002075 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002076 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00002077
2078 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
2079 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
2080 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002081}
2082
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002083GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002084 DrawCategory category) {
2085 if (category != fLastDrawCategory) {
2086 flushDrawBuffer();
2087 fLastDrawCategory = category;
2088 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002089 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002090 GrDrawTarget* target = fGpu;
2091 switch (category) {
2092 case kText_DrawCategory:
2093#if DEFER_TEXT_RENDERING
2094 target = fDrawBuffer;
2095 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2096#else
2097 target = fGpu;
2098#endif
2099 break;
2100 case kUnbuffered_DrawCategory:
2101 target = fGpu;
2102 break;
2103 case kBuffered_DrawCategory:
2104 target = fDrawBuffer;
2105 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2106 break;
2107 }
2108 return target;
2109}
2110
bsalomon@google.com289533a2011-10-27 12:34:25 +00002111GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
2112 GrPathFill fill,
2113 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00002114 if (NULL == fPathRendererChain) {
2115 fPathRendererChain =
2116 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
2117 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00002118 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
2119 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00002120}
2121
bsalomon@google.com27847de2011-02-22 20:59:41 +00002122////////////////////////////////////////////////////////////////////////////////
2123
bsalomon@google.com27847de2011-02-22 20:59:41 +00002124void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002125 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002126 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002127 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002128}
2129
2130GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002131 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002132}
2133
2134const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002135 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002136}
2137
2138const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002139 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002140}
2141
2142void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002143 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002144}
2145
2146void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002147 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002148}
2149
2150static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2151 intptr_t mask = 1 << shift;
2152 if (pred) {
2153 bits |= mask;
2154 } else {
2155 bits &= ~mask;
2156 }
2157 return bits;
2158}
2159
2160void GrContext::resetStats() {
2161 fGpu->resetStats();
2162}
2163
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002164const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002165 return fGpu->getStats();
2166}
2167
2168void GrContext::printStats() const {
2169 fGpu->printStats();
2170}
2171
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002172GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002173 fGpu = gpu;
2174 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002175 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002176
bsalomon@google.com30085192011-08-19 15:42:31 +00002177 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002178
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002179 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2180 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002181 fFontCache = new GrFontCache(fGpu);
2182
2183 fLastDrawCategory = kUnbuffered_DrawCategory;
2184
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002185 fDrawBuffer = NULL;
2186 fDrawBufferVBAllocPool = NULL;
2187 fDrawBufferIBAllocPool = NULL;
2188
bsalomon@google.com205d4602011-04-25 12:43:45 +00002189 fAAFillRectIndexBuffer = NULL;
2190 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002191
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002192 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2193 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002194 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2195 }
2196 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002197
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002198 this->setupDrawBuffer();
2199}
2200
2201void GrContext::setupDrawBuffer() {
2202
2203 GrAssert(NULL == fDrawBuffer);
2204 GrAssert(NULL == fDrawBufferVBAllocPool);
2205 GrAssert(NULL == fDrawBufferIBAllocPool);
2206
bsalomon@google.com27847de2011-02-22 20:59:41 +00002207#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002208 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002209 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002210 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2211 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002212 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002213 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002214 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002215 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2216
bsalomon@google.com471d4712011-08-23 15:45:25 +00002217 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2218 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002219 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002220#endif
2221
2222#if BATCH_RECT_TO_RECT
2223 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2224#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002225}
2226
bsalomon@google.com27847de2011-02-22 20:59:41 +00002227GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2228 GrDrawTarget* target;
2229#if DEFER_TEXT_RENDERING
2230 target = prepareToDraw(paint, kText_DrawCategory);
2231#else
2232 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2233#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002234 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002235 return target;
2236}
2237
2238const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2239 return fGpu->getQuadIndexBuffer();
2240}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002241
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002242void GrContext::convolveInX(GrTexture* texture,
2243 const SkRect& rect,
2244 const float* kernel,
2245 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002246 ASSERT_OWNED_RESOURCE(texture);
2247
bsalomon@google.com99621082011-11-15 16:47:16 +00002248 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002249 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2250}
2251
2252void GrContext::convolveInY(GrTexture* texture,
2253 const SkRect& rect,
2254 const float* kernel,
2255 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002256 ASSERT_OWNED_RESOURCE(texture);
2257
bsalomon@google.com99621082011-11-15 16:47:16 +00002258 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002259 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2260}
2261
2262void GrContext::convolve(GrTexture* texture,
2263 const SkRect& rect,
2264 float imageIncrement[2],
2265 const float* kernel,
2266 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002267 ASSERT_OWNED_RESOURCE(texture);
2268
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002269 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002270 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002271 GrMatrix sampleM;
2272 sampleM.setIDiv(texture->width(), texture->height());
2273 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2274 GrSamplerState::kConvolution_Filter,
2275 sampleM);
2276 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2277 kernel,
2278 imageIncrement);
2279
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002280 drawState->setViewMatrix(GrMatrix::I());
2281 drawState->setTexture(0, texture);
2282 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002283 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002284 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2285}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002286
2287///////////////////////////////////////////////////////////////////////////////