blob: 518698e2140fa2d6092e5c25f0f9f66cdda7b3b6 [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;
1686 GrRect dstRect = GrRect::MakeLTRB(pathBounds.fLeft,
1687 pathBounds.fTop,
1688 pathBounds.fRight,
1689 pathBounds.fBottom);
1690 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1691 target->drawState()->setTexture(kPathMaskStage, NULL);
1692 if (GrIsFillInverted(fill)) {
1693 draw_around_inv_path(target, stageMask,
1694 clipBounds, pathBounds);
1695 }
1696 return;
1697 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001698 }
1699 } else {
1700 pr = this->getPathRenderer(path, fill, false);
1701 }
1702
bsalomon@google.com30085192011-08-19 15:42:31 +00001703 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001704#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001705 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001706#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001707 return;
1708 }
1709
bsalomon@google.com289533a2011-10-27 12:34:25 +00001710 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001711
bsalomon@google.com289533a2011-10-27 12:34:25 +00001712 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001713 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001714 GrIRect pathBounds;
1715 GrIRect clipBounds;
1716 if (!get_path_and_clip_bounds(target, path, translate,
1717 &pathBounds, &clipBounds)) {
1718 return;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001719 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001720 OffscreenRecord record;
bsalomon@google.com150d2842012-01-12 20:19:56 +00001721 if (this->prepareForOffscreenAA(target, needsStencil, pathBounds,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001722 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001723 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1724 for (int ty = 0; ty < record.fTileCountY; ++ty) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001725 this->setupOffscreenAAPass1(target, pathBounds,
1726 tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001727 pr->drawPath(0);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001728 this->doOffscreenAAPass2(target, paint, pathBounds,
1729 tx, ty, &record);
bsalomon@google.com91958362011-06-13 17:58:13 +00001730 }
1731 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001732 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001733 if (GrIsFillInverted(fill)) {
1734 draw_around_inv_path(target, stageMask, clipBounds, pathBounds);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001735 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001736 return;
1737 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001738 }
1739 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001740}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001741
bsalomon@google.com27847de2011-02-22 20:59:41 +00001742////////////////////////////////////////////////////////////////////////////////
1743
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001744void GrContext::flush(int flagsBitfield) {
1745 if (kDiscard_FlushBit & flagsBitfield) {
1746 fDrawBuffer->reset();
1747 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001748 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001749 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001750 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001751 fGpu->forceRenderTargetFlush();
1752 }
1753}
1754
1755void GrContext::flushText() {
1756 if (kText_DrawCategory == fLastDrawCategory) {
1757 flushDrawBuffer();
1758 }
1759}
1760
1761void GrContext::flushDrawBuffer() {
1762#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001763 if (fDrawBuffer) {
1764 fDrawBuffer->playback(fGpu);
1765 fDrawBuffer->reset();
1766 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001767#endif
1768}
1769
bsalomon@google.com6f379512011-11-16 20:36:03 +00001770void GrContext::internalWriteTexturePixels(GrTexture* texture,
1771 int left, int top,
1772 int width, int height,
1773 GrPixelConfig config,
1774 const void* buffer,
1775 size_t rowBytes,
1776 uint32_t flags) {
1777 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001778 ASSERT_OWNED_RESOURCE(texture);
1779
bsalomon@google.com6f379512011-11-16 20:36:03 +00001780 if (!(kDontFlush_PixelOpsFlag & flags)) {
1781 this->flush();
1782 }
1783 // TODO: use scratch texture to perform conversion
1784 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1785 GrPixelConfigIsUnpremultiplied(config)) {
1786 return;
1787 }
1788
1789 fGpu->writeTexturePixels(texture, left, top, width, height,
1790 config, buffer, rowBytes);
1791}
1792
1793bool GrContext::internalReadTexturePixels(GrTexture* texture,
1794 int left, int top,
1795 int width, int height,
1796 GrPixelConfig config,
1797 void* buffer,
1798 size_t rowBytes,
1799 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001800 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001801 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001802
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001803 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001804 GrRenderTarget* target = texture->asRenderTarget();
1805 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001806 return this->internalReadRenderTargetPixels(target,
1807 left, top, width, height,
1808 config, buffer, rowBytes,
1809 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001810 } else {
1811 return false;
1812 }
1813}
1814
bsalomon@google.com6f379512011-11-16 20:36:03 +00001815bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1816 int left, int top,
1817 int width, int height,
1818 GrPixelConfig config,
1819 void* buffer,
1820 size_t rowBytes,
1821 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001822 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001823 ASSERT_OWNED_RESOURCE(target);
1824
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001825 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001826 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001827 if (NULL == target) {
1828 return false;
1829 }
1830 }
1831
1832 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1833 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1834 // not supported at this time.
1835 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1836 !GrPixelConfigIsUnpremultiplied(config)) {
1837 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001838 }
1839
bsalomon@google.com6f379512011-11-16 20:36:03 +00001840 if (!(kDontFlush_PixelOpsFlag & flags)) {
1841 this->flush();
1842 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001843
1844 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001845 bool swapRAndB = NULL != src &&
1846 fGpu->preferredReadPixelsConfig(config) ==
1847 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001848
1849 bool flipY = NULL != src &&
1850 fGpu->readPixelsWillPayForYFlip(target, left, top,
1851 width, height, config,
1852 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001853 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1854 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001855
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001856 if (NULL == src && alphaConversion) {
1857 // we should fallback to cpu conversion here. This could happen when
1858 // we were given an external render target by the client that is not
1859 // also a texture (e.g. FBO 0 in GL)
1860 return false;
1861 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001862 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001863 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001864 if (flipY || swapRAndB || alphaConversion) {
1865 GrAssert(NULL != src);
1866 if (swapRAndB) {
1867 config = GrPixelConfigSwapRAndB(config);
1868 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001869 }
1870 // Make the scratch a render target because we don't have a robust
1871 // readTexturePixels as of yet (it calls this function).
1872 const GrTextureDesc desc = {
1873 kRenderTarget_GrTextureFlagBit,
1874 kNone_GrAALevel,
1875 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001876 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001877 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001878
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001879 // When a full readback is faster than a partial we could always make
1880 // the scratch exactly match the passed rect. However, if we see many
1881 // different size rectangles we will trash our texture cache and pay the
1882 // cost of creating and destroying many textures. So, we only request
1883 // an exact match when the caller is reading an entire RT.
1884 ScratchTexMatch match = kApprox_ScratchTexMatch;
1885 if (0 == left &&
1886 0 == top &&
1887 target->width() == width &&
1888 target->height() == height &&
1889 fGpu->fullReadPixelsIsFasterThanPartial()) {
1890 match = kExact_ScratchTexMatch;
1891 }
1892 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001893 GrTexture* texture = ast.texture();
1894 if (!texture) {
1895 return false;
1896 }
1897 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001898 GrAssert(NULL != target);
1899
1900 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001901 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001902 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001903 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001904
bsalomon@google.comc4364992011-11-07 15:54:49 +00001905 GrMatrix matrix;
1906 if (flipY) {
1907 matrix.setTranslate(SK_Scalar1 * left,
1908 SK_Scalar1 * (top + height));
1909 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1910 } else {
1911 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1912 }
1913 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001914 drawState->sampler(0)->reset(matrix);
1915 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001916 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001917 GrRect rect;
1918 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1919 fGpu->drawSimpleRect(rect, NULL, 0x1);
1920 left = 0;
1921 top = 0;
1922 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001923 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001924 left, top, width, height,
1925 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001926}
1927
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001928void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1929 if (NULL == src || NULL == dst) {
1930 return;
1931 }
1932 ASSERT_OWNED_RESOURCE(src);
1933
1934 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001935 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001936 reset_draw_state(drawState);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001937 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001938 GrMatrix sampleM;
1939 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001940 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001941 drawState->sampler(0)->reset(sampleM);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001942 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1943 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1944}
1945
bsalomon@google.com6f379512011-11-16 20:36:03 +00001946void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1947 int left, int top,
1948 int width, int height,
1949 GrPixelConfig config,
1950 const void* buffer,
1951 size_t rowBytes,
1952 uint32_t flags) {
1953 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001954 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001955
1956 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001957 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001958 if (NULL == target) {
1959 return;
1960 }
1961 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001962
1963 // TODO: when underlying api has a direct way to do this we should use it
1964 // (e.g. glDrawPixels on desktop GL).
1965
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001966 // If the RT is also a texture and we don't have to do PM/UPM conversion
1967 // then take the texture path, which we expect to be at least as fast or
1968 // faster since it doesn't use an intermediate texture as we do below.
1969
1970#if !GR_MAC_BUILD
1971 // At least some drivers on the Mac get confused when glTexImage2D is called
1972 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1973 // determine what OS versions and/or HW is affected.
1974 if (NULL != target->asTexture() &&
1975 GrPixelConfigIsUnpremultiplied(target->config()) ==
1976 GrPixelConfigIsUnpremultiplied(config)) {
1977
1978 this->internalWriteTexturePixels(target->asTexture(),
1979 left, top, width, height,
1980 config, buffer, rowBytes, flags);
1981 return;
1982 }
1983#endif
1984
1985 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1986 GrPixelConfigSwapRAndB(config);
1987 if (swapRAndB) {
1988 config = GrPixelConfigSwapRAndB(config);
1989 }
1990
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001991 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001992 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001994 GrAutoScratchTexture ast(this, desc);
1995 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001996 if (NULL == texture) {
1997 return;
1998 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001999 this->internalWriteTexturePixels(texture, 0, 0, width, height,
2000 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002002 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002003 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002004 reset_draw_state(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002005
2006 GrMatrix matrix;
2007 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002008 drawState->setViewMatrix(matrix);
2009 drawState->setRenderTarget(target);
2010 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002011
bsalomon@google.com5c638652011-07-18 19:31:59 +00002012 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002013 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2014 GrSamplerState::kNearest_Filter,
2015 matrix);
2016 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002017
2018 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
2019 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002020 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00002021 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
2022 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00002023 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00002024 return;
2025 }
2026 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
2027 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
2028}
2029////////////////////////////////////////////////////////////////////////////////
2030
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002031void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002032 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002033
2034 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
2035 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002036 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002037 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002038 if (paint.getTexture(i)) {
2039 *drawState->sampler(s) = paint.getTextureSampler(i);
2040 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002041 }
2042
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002043 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002044
2045 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
2046 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002047 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002048 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00002049 if (paint.getMask(i)) {
2050 *drawState->sampler(s) = paint.getMaskSampler(i);
2051 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00002052 }
2053
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002054 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002055
2056 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002057 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002058 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002059 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002060 }
2061 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002062 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002063 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002064 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002065 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002066 if (paint.fColorMatrixEnabled) {
2067 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
2068 } else {
2069 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
2070 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002071 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002072 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00002073 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00002074
2075 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
2076 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
2077 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00002078}
2079
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002080GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002081 DrawCategory category) {
2082 if (category != fLastDrawCategory) {
2083 flushDrawBuffer();
2084 fLastDrawCategory = category;
2085 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002086 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002087 GrDrawTarget* target = fGpu;
2088 switch (category) {
2089 case kText_DrawCategory:
2090#if DEFER_TEXT_RENDERING
2091 target = fDrawBuffer;
2092 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2093#else
2094 target = fGpu;
2095#endif
2096 break;
2097 case kUnbuffered_DrawCategory:
2098 target = fGpu;
2099 break;
2100 case kBuffered_DrawCategory:
2101 target = fDrawBuffer;
2102 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
2103 break;
2104 }
2105 return target;
2106}
2107
bsalomon@google.com289533a2011-10-27 12:34:25 +00002108GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
2109 GrPathFill fill,
2110 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00002111 if (NULL == fPathRendererChain) {
2112 fPathRendererChain =
2113 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
2114 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00002115 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
2116 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00002117}
2118
bsalomon@google.com27847de2011-02-22 20:59:41 +00002119////////////////////////////////////////////////////////////////////////////////
2120
bsalomon@google.com27847de2011-02-22 20:59:41 +00002121void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002122 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002123 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002124 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002125}
2126
2127GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002128 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002129}
2130
2131const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002132 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002133}
2134
2135const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002136 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002137}
2138
2139void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002140 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002141}
2142
2143void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002144 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002145}
2146
2147static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2148 intptr_t mask = 1 << shift;
2149 if (pred) {
2150 bits |= mask;
2151 } else {
2152 bits &= ~mask;
2153 }
2154 return bits;
2155}
2156
2157void GrContext::resetStats() {
2158 fGpu->resetStats();
2159}
2160
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002161const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002162 return fGpu->getStats();
2163}
2164
2165void GrContext::printStats() const {
2166 fGpu->printStats();
2167}
2168
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002169GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002170 fGpu = gpu;
2171 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002172 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002173
bsalomon@google.com30085192011-08-19 15:42:31 +00002174 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002175
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002176 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2177 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002178 fFontCache = new GrFontCache(fGpu);
2179
2180 fLastDrawCategory = kUnbuffered_DrawCategory;
2181
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002182 fDrawBuffer = NULL;
2183 fDrawBufferVBAllocPool = NULL;
2184 fDrawBufferIBAllocPool = NULL;
2185
bsalomon@google.com205d4602011-04-25 12:43:45 +00002186 fAAFillRectIndexBuffer = NULL;
2187 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002188
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002189 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2190 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002191 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2192 }
2193 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002194
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002195 this->setupDrawBuffer();
2196}
2197
2198void GrContext::setupDrawBuffer() {
2199
2200 GrAssert(NULL == fDrawBuffer);
2201 GrAssert(NULL == fDrawBufferVBAllocPool);
2202 GrAssert(NULL == fDrawBufferIBAllocPool);
2203
bsalomon@google.com27847de2011-02-22 20:59:41 +00002204#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002205 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002206 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002207 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2208 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002209 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002210 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002211 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002212 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2213
bsalomon@google.com471d4712011-08-23 15:45:25 +00002214 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2215 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002216 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002217#endif
2218
2219#if BATCH_RECT_TO_RECT
2220 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2221#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002222}
2223
bsalomon@google.com27847de2011-02-22 20:59:41 +00002224GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2225 GrDrawTarget* target;
2226#if DEFER_TEXT_RENDERING
2227 target = prepareToDraw(paint, kText_DrawCategory);
2228#else
2229 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2230#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002231 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002232 return target;
2233}
2234
2235const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2236 return fGpu->getQuadIndexBuffer();
2237}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002238
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002239void GrContext::convolveInX(GrTexture* texture,
2240 const SkRect& rect,
2241 const float* kernel,
2242 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002243 ASSERT_OWNED_RESOURCE(texture);
2244
bsalomon@google.com99621082011-11-15 16:47:16 +00002245 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002246 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2247}
2248
2249void GrContext::convolveInY(GrTexture* texture,
2250 const SkRect& rect,
2251 const float* kernel,
2252 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002253 ASSERT_OWNED_RESOURCE(texture);
2254
bsalomon@google.com99621082011-11-15 16:47:16 +00002255 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002256 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2257}
2258
2259void GrContext::convolve(GrTexture* texture,
2260 const SkRect& rect,
2261 float imageIncrement[2],
2262 const float* kernel,
2263 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002264 ASSERT_OWNED_RESOURCE(texture);
2265
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002266 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002267 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002268 GrMatrix sampleM;
2269 sampleM.setIDiv(texture->width(), texture->height());
2270 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2271 GrSamplerState::kConvolution_Filter,
2272 sampleM);
2273 drawState->sampler(0)->setConvolutionParams(kernelWidth,
2274 kernel,
2275 imageIncrement);
2276
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002277 drawState->setViewMatrix(GrMatrix::I());
2278 drawState->setTexture(0, texture);
2279 drawState->setAlpha(0xFF);
bsalomon@google.com6b67e212011-12-09 16:10:24 +00002280 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002281 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2282}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002283
2284///////////////////////////////////////////////////////////////////////////////