blob: de80f654a764dd6c4b4ba01cd785a126152a86bb [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
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000021#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000022#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023
bsalomon@google.com91958362011-06-13 17:58:13 +000024// Using MSAA seems to be slower for some yet unknown reason.
25#define PREFER_MSAA_OFFSCREEN_AA 0
26#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000027
bsalomon@google.com27847de2011-02-22 20:59:41 +000028#define DEFER_TEXT_RENDERING 1
29
30#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
bsalomon@google.comd46e2422011-09-23 17:40:07 +000032// When we're using coverage AA but the blend is incompatible (given gpu
33// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000034#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000035
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000036static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
37static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000038
39static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
40static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
41
42// We are currently only batching Text and drawRectToRect, both
43// of which use the quad index buffer.
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
46
bsalomon@google.combc4b6542011-11-19 13:56:11 +000047#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
48
bsalomon@google.com05ef5102011-05-02 21:14:59 +000049GrContext* GrContext::Create(GrEngine engine,
50 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000051 GrContext* ctx = NULL;
52 GrGpu* fGpu = GrGpu::Create(engine, context3D);
53 if (NULL != fGpu) {
54 ctx = new GrContext(fGpu);
55 fGpu->unref();
56 }
57 return ctx;
58}
59
bsalomon@google.com27847de2011-02-22 20:59:41 +000060GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000061 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000062 delete fTextureCache;
63 delete fFontCache;
64 delete fDrawBuffer;
65 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000066 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000067
bsalomon@google.com205d4602011-04-25 12:43:45 +000068 GrSafeUnref(fAAFillRectIndexBuffer);
69 GrSafeUnref(fAAStrokeRectIndexBuffer);
70 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000071 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000072}
73
bsalomon@google.com8fe72472011-03-30 21:26:44 +000074void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000075 contextDestroyed();
76 this->setupDrawBuffer();
77}
78
79void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000080 // abandon first to so destructors
81 // don't try to free the resources in the API.
82 fGpu->abandonResources();
83
bsalomon@google.com30085192011-08-19 15:42:31 +000084 // a path renderer may be holding onto resources that
85 // are now unusable
86 GrSafeSetNull(fPathRendererChain);
87
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBuffer;
89 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferVBAllocPool;
92 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000093
bsalomon@google.com8fe72472011-03-30 21:26:44 +000094 delete fDrawBufferIBAllocPool;
95 fDrawBufferIBAllocPool = NULL;
96
bsalomon@google.com205d4602011-04-25 12:43:45 +000097 GrSafeSetNull(fAAFillRectIndexBuffer);
98 GrSafeSetNull(fAAStrokeRectIndexBuffer);
99
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100 fTextureCache->removeAll();
101 fFontCache->freeAll();
102 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000103}
104
105void GrContext::resetContext() {
106 fGpu->markContextDirty();
107}
108
109void GrContext::freeGpuResources() {
110 this->flush();
111 fTextureCache->removeAll();
112 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000113 // a path renderer may be holding onto resources
114 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000115}
116
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000117////////////////////////////////////////////////////////////////////////////////
118
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000119int GrContext::PaintStageVertexLayoutBits(
120 const GrPaint& paint,
121 const bool hasTexCoords[GrPaint::kTotalStages]) {
122 int stageMask = paint.getActiveStageMask();
123 int layout = 0;
124 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
125 if ((1 << i) & stageMask) {
126 if (NULL != hasTexCoords && hasTexCoords[i]) {
127 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
128 } else {
129 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
130 }
131 }
132 }
133 return layout;
134}
135
136
137////////////////////////////////////////////////////////////////////////////////
138
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000139enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000140 // flags for textures
141 kNPOTBit = 0x1,
142 kFilterBit = 0x2,
143 kScratchBit = 0x4,
144
145 // resource type
146 kTextureBit = 0x8,
147 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000148};
149
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000150GrTexture* GrContext::TextureCacheEntry::texture() const {
151 if (NULL == fEntry) {
152 return NULL;
153 } else {
154 return (GrTexture*) fEntry->resource();
155 }
156}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000157
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000158namespace {
159// returns true if this is a "special" texture because of gpu NPOT limitations
160bool gen_texture_key_values(const GrGpu* gpu,
161 const GrSamplerState& sampler,
162 GrContext::TextureKey clientKey,
163 int width,
164 int height,
165 bool scratch,
166 uint32_t v[4]) {
167 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
168 // we assume we only need 16 bits of width and height
169 // assert that texture creation will fail anyway if this assumption
170 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000171 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000172 v[0] = clientKey & 0xffffffffUL;
173 v[1] = (clientKey >> 32) & 0xffffffffUL;
174 v[2] = width | (height << 16);
175
176 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000177 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000178 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
179
180 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
181 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
182
183 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000184 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000185 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000187 }
188 }
189 }
190
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191 if (scratch) {
192 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000193 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000195 v[3] |= kTextureBit;
196
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000197 return v[3] & kNPOTBit;
198}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000199
200// we should never have more than one stencil buffer with same combo of
201// (width,height,samplecount)
202void gen_stencil_key_values(int width, int height,
203 int sampleCnt, uint32_t v[4]) {
204 v[0] = width;
205 v[1] = height;
206 v[2] = sampleCnt;
207 v[3] = kStencilBufferBit;
208}
209
210void gen_stencil_key_values(const GrStencilBuffer* sb,
211 uint32_t v[4]) {
212 gen_stencil_key_values(sb->width(), sb->height(),
213 sb->numSamples(), v);
214}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000215
216// This should be subsumed by a future version of GrDrawState
217// It does not reset stage textures/samplers or per-vertex-edge-aa state since
218// they aren't used unless the vertex layout references them.
219// It also doesn't set the render target.
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000220void reset_target_state(GrDrawTarget* target){
221 target->setViewMatrix(GrMatrix::I());
222 target->setColorFilter(0, SkXfermode::kDst_Mode);
223 target->disableState(GrDrawTarget::kDither_StateBit |
224 GrDrawTarget::kHWAntialias_StateBit |
225 GrDrawTarget::kClip_StateBit |
226 GrDrawTarget::kNoColorWrites_StateBit |
227 GrDrawTarget::kEdgeAAConcave_StateBit);
228 target->setEdgeAAData(NULL, 0);
229 target->disableStencil();
230 target->setAlpha(0xFF);
231 target->setBlendFunc(kOne_BlendCoeff,
232 kZero_BlendCoeff);
233 target->setFirstCoverageStage(GrDrawState::kNumStages);
234 target->setDrawFace(GrDrawState::kBoth_DrawFace);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000235}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000236}
237
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000238GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
239 int width,
240 int height,
241 const GrSamplerState& sampler) {
242 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,
252 const GrSamplerState& sampler) const {
253 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.com50398bf2011-07-26 20:45:30 +0000314GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000315 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000316 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000317 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000318 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000319
320#if GR_DUMP_TEXTURE_UPLOAD
321 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
322#endif
323
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000324 TextureCacheEntry entry;
325 uint32_t v[4];
326 bool special = gen_texture_key_values(fGpu, sampler, key,
327 desc.fWidth, desc.fHeight, false, v);
328 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000329
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000330 if (special) {
331 TextureCacheEntry clampEntry =
332 findAndLockTexture(key, desc.fWidth, desc.fHeight,
bsalomon@google.com97912912011-12-06 16:30:36 +0000333 GrSamplerState::ClampNearest());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000334
335 if (NULL == clampEntry.texture()) {
336 clampEntry = createAndLockTexture(key,
bsalomon@google.com97912912011-12-06 16:30:36 +0000337 GrSamplerState::ClampNearest(),
bsalomon@google.com27847de2011-02-22 20:59:41 +0000338 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000339 GrAssert(NULL != clampEntry.texture());
340 if (NULL == clampEntry.texture()) {
341 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000342 }
343 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000344 GrTextureDesc rtDesc = desc;
345 rtDesc.fFlags = rtDesc.fFlags |
346 kRenderTarget_GrTextureFlagBit |
347 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000348 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
349 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000350
351 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
352
353 if (NULL != texture) {
354 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000355 reset_target_state(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000356
bsalomon@google.com27847de2011-02-22 20:59:41 +0000357 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000358 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000359
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000360 GrSamplerState::Filter filter;
361 // if filtering is not desired then we want to ensure all
362 // texels in the resampled image are copies of texels from
363 // the original.
364 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
365 filter = GrSamplerState::kNearest_Filter;
366 } else {
367 filter = GrSamplerState::kBilinear_Filter;
368 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000369 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000370 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000371 fGpu->setSamplerState(0, stretchSampler);
372
373 static const GrVertexLayout layout =
374 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
375 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
376
377 if (arg.succeeded()) {
378 GrPoint* verts = (GrPoint*) arg.vertices();
379 verts[0].setIRectFan(0, 0,
380 texture->width(),
381 texture->height(),
382 2*sizeof(GrPoint));
383 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
384 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
385 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000386 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000387 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000388 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389 } else {
390 // TODO: Our CPU stretch doesn't filter. But we create separate
391 // stretched textures when the sampler state is either filtered or
392 // not. Either implement filtered stretch blit on CPU or just create
393 // one when FBO case fails.
394
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000395 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000396 // no longer need to clamp at min RT size.
397 rtDesc.fWidth = GrNextPow2(desc.fWidth);
398 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000399 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000400 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000401 rtDesc.fWidth *
402 rtDesc.fHeight);
403 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
404 srcData, desc.fWidth, desc.fHeight, bpp);
405
406 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
407
408 GrTexture* texture = fGpu->createTexture(rtDesc,
409 stretchedPixels.get(),
410 stretchedRowBytes);
411 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000412 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000413 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415
416 } else {
417 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
418 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000419 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000420 }
421 }
422 return entry;
423}
424
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000425namespace {
426inline void gen_scratch_tex_key_values(const GrGpu* gpu,
427 const GrTextureDesc& desc,
428 uint32_t v[4]) {
429 // Instead of a client-provided key of the texture contents
430 // we create a key of from the descriptor.
431 GrContext::TextureKey descKey = desc.fAALevel |
432 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000433 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 // this code path isn't friendly to tiling with NPOT restricitons
435 // We just pass ClampNoFilter()
bsalomon@google.com97912912011-12-06 16:30:36 +0000436 gen_texture_key_values(gpu, GrSamplerState::ClampNearest(), descKey,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000437 desc.fWidth, desc.fHeight, true, v);
438}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000439}
440
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441GrContext::TextureCacheEntry GrContext::lockScratchTexture(
442 const GrTextureDesc& inDesc,
443 ScratchTexMatch match) {
444
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000445 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000446 if (kExact_ScratchTexMatch != match) {
447 // bin by pow2 with a reasonable min
448 static const int MIN_SIZE = 256;
449 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
450 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
451 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000452
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000453 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000454 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
455
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000456 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000457 int origWidth = desc.fWidth;
458 int origHeight = desc.fHeight;
459 bool doubledW = false;
460 bool doubledH = false;
461
462 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000463 uint32_t v[4];
464 gen_scratch_tex_key_values(fGpu, desc, v);
465 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000466 entry = fTextureCache->findAndLock(key,
467 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000468 // if we miss, relax the fit of the flags...
469 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000470 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000471 break;
472 }
473 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
474 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
475 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
476 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
477 } else if (!doubledW) {
478 desc.fFlags = inDesc.fFlags;
479 desc.fWidth *= 2;
480 doubledW = true;
481 } else if (!doubledH) {
482 desc.fFlags = inDesc.fFlags;
483 desc.fWidth = origWidth;
484 desc.fHeight *= 2;
485 doubledH = true;
486 } else {
487 break;
488 }
489
490 } while (true);
491
492 if (NULL == entry) {
493 desc.fFlags = inDesc.fFlags;
494 desc.fWidth = origWidth;
495 desc.fHeight = origHeight;
496 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
497 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000498 uint32_t v[4];
499 gen_scratch_tex_key_values(fGpu, desc, v);
500 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000501 entry = fTextureCache->createAndLock(key, texture);
502 }
503 }
504
505 // If the caller gives us the same desc/sampler twice we don't want
506 // to return the same texture the second time (unless it was previously
507 // released). So we detach the entry from the cache and reattach at release.
508 if (NULL != entry) {
509 fTextureCache->detach(entry);
510 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000511 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000512}
513
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000514void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000515 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000516 // If this is a scratch texture we detached it from the cache
517 // while it was locked (to avoid two callers simultaneously getting
518 // the same texture).
519 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
520 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000521 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000522 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000523 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000524}
525
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000526GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000527 void* srcData,
528 size_t rowBytes) {
529 return fGpu->createTexture(desc, srcData, rowBytes);
530}
531
532void GrContext::getTextureCacheLimits(int* maxTextures,
533 size_t* maxTextureBytes) const {
534 fTextureCache->getLimits(maxTextures, maxTextureBytes);
535}
536
537void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
538 fTextureCache->setLimits(maxTextures, maxTextureBytes);
539}
540
bsalomon@google.com91958362011-06-13 17:58:13 +0000541int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000542 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000543}
544
545int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000546 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000547}
548
549///////////////////////////////////////////////////////////////////////////////
550
bsalomon@google.come269f212011-11-07 13:29:52 +0000551GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
552 return fGpu->createPlatformTexture(desc);
553}
554
555GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
556 return fGpu->createPlatformRenderTarget(desc);
557}
558
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000559GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
560 // validate flags here so that GrGpu subclasses don't have to check
561 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
562 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000563 return NULL;
564 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000565 if (desc.fSampleCnt &&
566 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000567 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000568 }
569 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
570 desc.fSampleCnt &&
571 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
572 return NULL;
573 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000574 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000575}
576
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000577///////////////////////////////////////////////////////////////////////////////
578
bsalomon@google.com27847de2011-02-22 20:59:41 +0000579bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000580 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000581 const GrDrawTarget::Caps& caps = fGpu->getCaps();
582 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000583 return false;
584 }
585
bsalomon@google.com27847de2011-02-22 20:59:41 +0000586 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
587
588 if (!isPow2) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000589 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
590 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000591 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000592 return false;
593 }
594 }
595 return true;
596}
597
598////////////////////////////////////////////////////////////////////////////////
599
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000600const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
601
bsalomon@google.com27847de2011-02-22 20:59:41 +0000602void GrContext::setClip(const GrClip& clip) {
603 fGpu->setClip(clip);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000604 fGpu->enableState(GrDrawTarget::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000605}
606
607void GrContext::setClip(const GrIRect& rect) {
608 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000609 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000610 fGpu->setClip(clip);
611}
612
613////////////////////////////////////////////////////////////////////////////////
614
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000615void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000616 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000617 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000618}
619
620void GrContext::drawPaint(const GrPaint& paint) {
621 // set rect to be big enough to fill the space, but not super-huge, so we
622 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000623 GrRect r;
624 r.setLTRB(0, 0,
625 GrIntToScalar(getRenderTarget()->width()),
626 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000627 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000628 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000629 SkTLazy<GrPaint> tmpPaint;
630 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000631 // We attempt to map r by the inverse matrix and draw that. mapRect will
632 // map the four corners and bound them with a new rect. This will not
633 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000634 if (!this->getMatrix().hasPerspective()) {
635 if (!fGpu->getViewInverse(&inverse)) {
636 GrPrintf("Could not invert matrix");
637 return;
638 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000639 inverse.mapRect(&r);
640 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000641 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
642 if (!fGpu->getViewInverse(&inverse)) {
643 GrPrintf("Could not invert matrix");
644 return;
645 }
646 tmpPaint.set(paint);
647 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
648 p = tmpPaint.get();
649 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000650 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000651 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000652 // by definition this fills the entire clip, no need for AA
653 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000654 if (!tmpPaint.isValid()) {
655 tmpPaint.set(paint);
656 p = tmpPaint.get();
657 }
658 GrAssert(p == tmpPaint.get());
659 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000660 }
661 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000662}
663
bsalomon@google.com205d4602011-04-25 12:43:45 +0000664////////////////////////////////////////////////////////////////////////////////
665
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000666namespace {
667inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
668 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
669}
670}
671
bsalomon@google.com91958362011-06-13 17:58:13 +0000672struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000673 enum Downsample {
674 k4x4TwoPass_Downsample,
675 k4x4SinglePass_Downsample,
676 kFSAA_Downsample
677 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000678 int fTileSizeX;
679 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000680 int fTileCountX;
681 int fTileCountY;
682 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000683 GrAutoScratchTexture fOffscreen0;
684 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000685 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000686 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000687};
688
bsalomon@google.com471d4712011-08-23 15:45:25 +0000689bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000690 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000691#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000692 return false;
693#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000694 // Line primitves are always rasterized as 1 pixel wide.
695 // Super-sampling would make them too thin but MSAA would be OK.
696 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000697 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000698 return false;
699 }
700 if (target->getRenderTarget()->isMultisampled()) {
701 return false;
702 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000703 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000704#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000705 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000706#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000707 return false;
708 }
709 return true;
710#endif
711}
712
bsalomon@google.com91958362011-06-13 17:58:13 +0000713bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000714 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000715 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000716 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000717 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000718
719 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000720
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000721 GrAssert(NULL == record->fOffscreen0.texture());
722 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000723 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000724
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000725 int boundW = boundRect.width();
726 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000727
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000728 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000729
730 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
731 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
732
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000733 if (requireStencil) {
734 desc.fFlags = kRenderTarget_GrTextureFlagBit;
735 } else {
736 desc.fFlags = kRenderTarget_GrTextureFlagBit |
737 kNoStencil_GrTextureFlagBit;
738 }
739
bsalomon@google.comc4364992011-11-07 15:54:49 +0000740 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000741
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000742 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000743 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000744 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000745 desc.fAALevel = kMed_GrAALevel;
746 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000747 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000748 OffscreenRecord::k4x4SinglePass_Downsample :
749 OffscreenRecord::k4x4TwoPass_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.com50398bf2011-07-26 20:45:30 +0000758 record->fOffscreen0.set(this, desc);
759 if (NULL == record->fOffscreen0.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.com50398bf2011-07-26 20:45:30 +0000766 record->fTileSizeX = record->fOffscreen0.texture()->width();
767 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000769 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000770 desc.fWidth /= 2;
771 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000772 record->fOffscreen1.set(this, desc);
773 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000774 return false;
775 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000776 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000777 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000778 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000779 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000780 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000781 record->fTileSizeX /= record->fScale;
782 record->fTileSizeY /= record->fScale;
783
784 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
785 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
786
tomhudson@google.com237a4612011-07-19 15:44:00 +0000787 record->fClip = target->getClip();
788
bsalomon@google.com91958362011-06-13 17:58:13 +0000789 target->saveCurrentDrawState(&record->fSavedState);
790 return true;
791}
792
793void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
794 const GrIRect& boundRect,
795 int tileX, int tileY,
796 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000797
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000798 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000799 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000800
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000801 GrPaint tempPaint;
802 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000803 this->setPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000804 target->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000805#if PREFER_MSAA_OFFSCREEN_AA
806 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
807#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000808
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000809 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 int left = boundRect.fLeft + tileX * record->fTileSizeX;
811 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000812 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
813 target->postConcatViewMatrix(transM);
814 GrMatrix scaleM;
815 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
816 target->postConcatViewMatrix(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000817
bsalomon@google.com91958362011-06-13 17:58:13 +0000818 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000819 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000820 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000821 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000822 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
823 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000824 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000825#if 0
826 // visualize tile boundaries by setting edges of offscreen to white
827 // and interior to tranparent. black.
828 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000829
bsalomon@google.com91958362011-06-13 17:58:13 +0000830 static const int gOffset = 2;
831 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
832 record->fScale * w - gOffset,
833 record->fScale * h - gOffset);
834 target->clear(&clear2, 0x0);
835#else
836 target->clear(&clear, 0x0);
837#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000838}
839
bsalomon@google.com91958362011-06-13 17:58:13 +0000840void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000841 const GrPaint& paint,
842 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000843 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000844 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000845 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000846 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000847 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000848 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000849 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
850 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000851 tileRect.fRight = (tileX == record->fTileCountX-1) ?
852 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000853 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000854 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
855 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000856 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000857
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000858 GrSamplerState::Filter filter;
859 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
860 filter = GrSamplerState::k4x4Downsample_Filter;
861 } else {
862 filter = GrSamplerState::kBilinear_Filter;
863 }
864
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000865 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +0000866 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000867
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000868 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000869 int scale;
870
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000871 enum {
872 kOffscreenStage = GrPaint::kTotalStages,
873 };
874
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000875 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000876 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000877 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000878 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000879
880 // Do 2x2 downsample from first to second
881 target->setTexture(kOffscreenStage, src);
882 target->setRenderTarget(dst);
883 target->setViewMatrix(GrMatrix::I());
884 sampleM.setScale(scale * GR_Scalar1 / src->width(),
885 scale * GR_Scalar1 / src->height());
886 sampler.setMatrix(sampleM);
887 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000888 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
889 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000890 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
891
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000892 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000893 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000894 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000895 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000896 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000897 } else {
898 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
899 record->fDownsample);
900 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000901 }
902
bsalomon@google.com91958362011-06-13 17:58:13 +0000903 // setup for draw back to main RT, we use the original
904 // draw state setup by the caller plus an additional coverage
905 // stage to handle the AA resolve. Also, we use an identity
906 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000907 int stageMask = paint.getActiveStageMask();
908
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000909 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000910 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000911
912 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000913 GrMatrix invVM;
914 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000915 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000916 }
917 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000918 // This is important when tiling, otherwise second tile's
919 // pass 1 view matrix will be incorrect.
920 GrDrawTarget::AutoViewMatrixRestore avmr(target);
921
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000922 target->setViewMatrix(GrMatrix::I());
923
924 target->setTexture(kOffscreenStage, src);
925 sampleM.setScale(scale * GR_Scalar1 / src->width(),
926 scale * GR_Scalar1 / src->height());
927 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000928 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
929 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000930 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000931 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000932
reed@google.com20efde72011-05-09 17:00:02 +0000933 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000934 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000935 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000936 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000937}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000938
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000939void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
940 GrPathRenderer* pr,
941 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000942 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000943}
944
945////////////////////////////////////////////////////////////////////////////////
946
bsalomon@google.com27847de2011-02-22 20:59:41 +0000947/* create a triangle strip that strokes the specified triangle. There are 8
948 unique vertices, but we repreat the last 2 to close up. Alternatively we
949 could use an indices array, and then only send 8 verts, but not sure that
950 would be faster.
951 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000952static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000953 GrScalar width) {
954 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000955 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000956
957 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
958 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
959 verts[2].set(rect.fRight - rad, rect.fTop + rad);
960 verts[3].set(rect.fRight + rad, rect.fTop - rad);
961 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
962 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
963 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
964 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
965 verts[8] = verts[0];
966 verts[9] = verts[1];
967}
968
bsalomon@google.com205d4602011-04-25 12:43:45 +0000969static void setInsetFan(GrPoint* pts, size_t stride,
970 const GrRect& r, GrScalar dx, GrScalar dy) {
971 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
972}
973
974static const uint16_t gFillAARectIdx[] = {
975 0, 1, 5, 5, 4, 0,
976 1, 2, 6, 6, 5, 1,
977 2, 3, 7, 7, 6, 2,
978 3, 0, 4, 4, 7, 3,
979 4, 5, 6, 6, 7, 4,
980};
981
982int GrContext::aaFillRectIndexCount() const {
983 return GR_ARRAY_COUNT(gFillAARectIdx);
984}
985
986GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
987 if (NULL == fAAFillRectIndexBuffer) {
988 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
989 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000990 if (NULL != fAAFillRectIndexBuffer) {
991 #if GR_DEBUG
992 bool updated =
993 #endif
994 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
995 sizeof(gFillAARectIdx));
996 GR_DEBUGASSERT(updated);
997 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000998 }
999 return fAAFillRectIndexBuffer;
1000}
1001
1002static const uint16_t gStrokeAARectIdx[] = {
1003 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
1004 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1005 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1006 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1007
1008 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1009 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1010 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1011 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1012
1013 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1014 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1015 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1016 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1017};
1018
1019int GrContext::aaStrokeRectIndexCount() const {
1020 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1021}
1022
1023GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1024 if (NULL == fAAStrokeRectIndexBuffer) {
1025 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1026 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001027 if (NULL != fAAStrokeRectIndexBuffer) {
1028 #if GR_DEBUG
1029 bool updated =
1030 #endif
1031 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1032 sizeof(gStrokeAARectIdx));
1033 GR_DEBUGASSERT(updated);
1034 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001035 }
1036 return fAAStrokeRectIndexBuffer;
1037}
1038
bsalomon@google.coma3108262011-10-10 14:08:47 +00001039static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1040 bool useCoverage) {
1041 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001042 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001043 if (NULL != target->getTexture(s)) {
1044 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1045 }
1046 }
1047 if (useCoverage) {
1048 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1049 } else {
1050 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1051 }
1052 return layout;
1053}
1054
bsalomon@google.com205d4602011-04-25 12:43:45 +00001055void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001056 const GrRect& devRect,
1057 bool useVertexCoverage) {
1058 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001059
1060 size_t vsize = GrDrawTarget::VertexSize(layout);
1061
1062 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001063 if (!geo.succeeded()) {
1064 GrPrintf("Failed to get space for vertices!\n");
1065 return;
1066 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001067 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1068 if (NULL == indexBuffer) {
1069 GrPrintf("Failed to create index buffer!\n");
1070 return;
1071 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001072
1073 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1074
1075 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1076 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1077
1078 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1079 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1080
1081 verts += sizeof(GrPoint);
1082 for (int i = 0; i < 4; ++i) {
1083 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1084 }
1085
bsalomon@google.coma3108262011-10-10 14:08:47 +00001086 GrColor innerColor;
1087 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001088 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001089 } else {
1090 innerColor = target->getColor();
1091 }
1092
bsalomon@google.com205d4602011-04-25 12:43:45 +00001093 verts += 4 * vsize;
1094 for (int i = 0; i < 4; ++i) {
1095 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1096 }
1097
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001098 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001099
1100 target->drawIndexed(kTriangles_PrimitiveType, 0,
1101 0, 8, this->aaFillRectIndexCount());
1102}
1103
bsalomon@google.coma3108262011-10-10 14:08:47 +00001104void GrContext::strokeAARect(GrDrawTarget* target,
1105 const GrRect& devRect,
1106 const GrVec& devStrokeSize,
1107 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001108 const GrScalar& dx = devStrokeSize.fX;
1109 const GrScalar& dy = devStrokeSize.fY;
1110 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1111 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1112
bsalomon@google.com205d4602011-04-25 12:43:45 +00001113 GrScalar spare;
1114 {
1115 GrScalar w = devRect.width() - dx;
1116 GrScalar h = devRect.height() - dy;
1117 spare = GrMin(w, h);
1118 }
1119
1120 if (spare <= 0) {
1121 GrRect r(devRect);
1122 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001123 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001124 return;
1125 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001126 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001127 size_t vsize = GrDrawTarget::VertexSize(layout);
1128
1129 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001130 if (!geo.succeeded()) {
1131 GrPrintf("Failed to get space for vertices!\n");
1132 return;
1133 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001134 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1135 if (NULL == indexBuffer) {
1136 GrPrintf("Failed to create index buffer!\n");
1137 return;
1138 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001139
1140 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1141
1142 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1143 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1144 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1145 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1146
1147 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1148 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1149 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1150 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1151
1152 verts += sizeof(GrPoint);
1153 for (int i = 0; i < 4; ++i) {
1154 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1155 }
1156
bsalomon@google.coma3108262011-10-10 14:08:47 +00001157 GrColor innerColor;
1158 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001159 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001160 } else {
1161 innerColor = target->getColor();
1162 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001163 verts += 4 * vsize;
1164 for (int i = 0; i < 8; ++i) {
1165 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1166 }
1167
1168 verts += 8 * vsize;
1169 for (int i = 0; i < 8; ++i) {
1170 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1171 }
1172
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001173 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001174 target->drawIndexed(kTriangles_PrimitiveType,
1175 0, 0, 16, aaStrokeRectIndexCount());
1176}
1177
reed@google.com20efde72011-05-09 17:00:02 +00001178/**
1179 * Returns true if the rects edges are integer-aligned.
1180 */
1181static bool isIRect(const GrRect& r) {
1182 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1183 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1184}
1185
bsalomon@google.com205d4602011-04-25 12:43:45 +00001186static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001187 const GrRect& rect,
1188 GrScalar width,
1189 const GrMatrix* matrix,
1190 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001191 GrRect* devRect,
1192 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001193 // we use a simple alpha ramp to do aa on axis-aligned rects
1194 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001195 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001196
bsalomon@google.coma3108262011-10-10 14:08:47 +00001197 // we are keeping around the "tweak the alpha" trick because
1198 // it is our only hope for the fixed-pipe implementation.
1199 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001200 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001201 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001202 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001203 if (target->getCaps().fSupportPerVertexCoverage) {
1204 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001205#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001206 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001207#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001208 return false;
1209 } else {
1210 *useVertexCoverage = true;
1211 }
1212 } else {
1213 GrPrintf("Rect AA dropped because no support for coverage.\n");
1214 return false;
1215 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001216 }
1217
1218 if (target->getRenderTarget()->isMultisampled()) {
1219 return false;
1220 }
1221
bsalomon@google.com471d4712011-08-23 15:45:25 +00001222 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001223 return false;
1224 }
1225
1226 if (!target->getViewMatrix().preservesAxisAlignment()) {
1227 return false;
1228 }
1229
1230 if (NULL != matrix &&
1231 !matrix->preservesAxisAlignment()) {
1232 return false;
1233 }
1234
1235 *combinedMatrix = target->getViewMatrix();
1236 if (NULL != matrix) {
1237 combinedMatrix->preConcat(*matrix);
1238 GrAssert(combinedMatrix->preservesAxisAlignment());
1239 }
1240
1241 combinedMatrix->mapRect(devRect, rect);
1242 devRect->sort();
1243
1244 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001245 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001246 } else {
1247 return true;
1248 }
1249}
1250
bsalomon@google.com27847de2011-02-22 20:59:41 +00001251void GrContext::drawRect(const GrPaint& paint,
1252 const GrRect& rect,
1253 GrScalar width,
1254 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001255 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001256
1257 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001258 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001259
bsalomon@google.com205d4602011-04-25 12:43:45 +00001260 GrRect devRect = rect;
1261 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001262 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001263 bool needAA = paint.fAntiAlias &&
1264 !this->getRenderTarget()->isMultisampled();
1265 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1266 &combinedMatrix, &devRect,
1267 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001268
1269 if (doAA) {
1270 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001271 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001272 GrMatrix inv;
1273 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001274 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001275 }
1276 }
1277 target->setViewMatrix(GrMatrix::I());
1278 if (width >= 0) {
1279 GrVec strokeSize;;
1280 if (width > 0) {
1281 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001282 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001283 strokeSize.setAbs(strokeSize);
1284 } else {
1285 strokeSize.set(GR_Scalar1, GR_Scalar1);
1286 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001287 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001288 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001289 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001290 }
1291 return;
1292 }
1293
bsalomon@google.com27847de2011-02-22 20:59:41 +00001294 if (width >= 0) {
1295 // TODO: consider making static vertex buffers for these cases.
1296 // Hairline could be done by just adding closing vertex to
1297 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001298 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1299
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300 static const int worstCaseVertCount = 10;
1301 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1302
1303 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001304 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001305 return;
1306 }
1307
1308 GrPrimitiveType primType;
1309 int vertCount;
1310 GrPoint* vertex = geo.positions();
1311
1312 if (width > 0) {
1313 vertCount = 10;
1314 primType = kTriangleStrip_PrimitiveType;
1315 setStrokeRectStrip(vertex, rect, width);
1316 } else {
1317 // hairline
1318 vertCount = 5;
1319 primType = kLineStrip_PrimitiveType;
1320 vertex[0].set(rect.fLeft, rect.fTop);
1321 vertex[1].set(rect.fRight, rect.fTop);
1322 vertex[2].set(rect.fRight, rect.fBottom);
1323 vertex[3].set(rect.fLeft, rect.fBottom);
1324 vertex[4].set(rect.fLeft, rect.fTop);
1325 }
1326
1327 GrDrawTarget::AutoViewMatrixRestore avmr;
1328 if (NULL != matrix) {
1329 avmr.set(target);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001330 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001331 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001332 }
1333
1334 target->drawNonIndexed(primType, 0, vertCount);
1335 } else {
1336 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001337 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001338 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1339 if (NULL == sqVB) {
1340 GrPrintf("Failed to create static rect vb.\n");
1341 return;
1342 }
1343 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1345 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001346 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001347 0, rect.height(), rect.fTop,
1348 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001349
1350 if (NULL != matrix) {
1351 m.postConcat(*matrix);
1352 }
1353
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001354 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001355 target->preConcatSamplerMatrices(stageMask, m);
1356
bsalomon@google.com27847de2011-02-22 20:59:41 +00001357 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1358 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001359 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001360 #endif
1361 }
1362}
1363
1364void GrContext::drawRectToRect(const GrPaint& paint,
1365 const GrRect& dstRect,
1366 const GrRect& srcRect,
1367 const GrMatrix* dstMatrix,
1368 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001369 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001370
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001371 // srcRect refers to paint's first texture
1372 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001373 drawRect(paint, dstRect, -1, dstMatrix);
1374 return;
1375 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001376
bsalomon@google.com27847de2011-02-22 20:59:41 +00001377 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1378
1379#if GR_STATIC_RECT_VB
1380 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001381
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001382 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001383 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1384
1385 GrMatrix m;
1386
1387 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1388 0, dstRect.height(), dstRect.fTop,
1389 0, 0, GrMatrix::I()[8]);
1390 if (NULL != dstMatrix) {
1391 m.postConcat(*dstMatrix);
1392 }
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001393 target->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001394
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001395 // srcRect refers to first stage
1396 int otherStageMask = paint.getActiveStageMask() &
1397 (~(1 << GrPaint::kFirstTextureStage));
1398 if (otherStageMask) {
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001399 target->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001400 }
1401
bsalomon@google.com27847de2011-02-22 20:59:41 +00001402 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1403 0, srcRect.height(), srcRect.fTop,
1404 0, 0, GrMatrix::I()[8]);
1405 if (NULL != srcMatrix) {
1406 m.postConcat(*srcMatrix);
1407 }
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001408 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001409
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001410 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1411 if (NULL == sqVB) {
1412 GrPrintf("Failed to create static rect vb.\n");
1413 return;
1414 }
1415 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001416 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1417#else
1418
1419 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001420#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001421 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001422#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1424#endif
1425
tomhudson@google.com93813632011-10-27 20:21:16 +00001426 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1427 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001428 srcRects[0] = &srcRect;
1429 srcMatrices[0] = srcMatrix;
1430
1431 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1432#endif
1433}
1434
1435void GrContext::drawVertices(const GrPaint& paint,
1436 GrPrimitiveType primitiveType,
1437 int vertexCount,
1438 const GrPoint positions[],
1439 const GrPoint texCoords[],
1440 const GrColor colors[],
1441 const uint16_t indices[],
1442 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001443 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001444
1445 GrDrawTarget::AutoReleaseGeometry geo;
1446
1447 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1448
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001449 bool hasTexCoords[GrPaint::kTotalStages] = {
1450 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1451 0 // remaining stages use positions
1452 };
1453
1454 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001455
1456 if (NULL != colors) {
1457 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001458 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001459 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460
1461 if (sizeof(GrPoint) != vertexSize) {
1462 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001463 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001464 return;
1465 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001466 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001467 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001468 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1469 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001470 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001471 NULL,
1472 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001473 void* curVertex = geo.vertices();
1474
1475 for (int i = 0; i < vertexCount; ++i) {
1476 *((GrPoint*)curVertex) = positions[i];
1477
1478 if (texOffsets[0] > 0) {
1479 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1480 }
1481 if (colorOffset > 0) {
1482 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1483 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001484 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001485 }
1486 } else {
1487 target->setVertexSourceToArray(layout, positions, vertexCount);
1488 }
1489
bsalomon@google.com91958362011-06-13 17:58:13 +00001490 // we don't currently apply offscreen AA to this path. Need improved
1491 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001492
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001493 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001494 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001495 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001496 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001497 target->drawNonIndexed(primitiveType, 0, vertexCount);
1498 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001499}
1500
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001501///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001502
reed@google.com07f3ee12011-05-16 17:21:57 +00001503void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1504 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001505
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001506 if (path.isEmpty()) {
1507#if GR_DEBUG
1508 GrPrintf("Empty path should have been caught by canvas.\n");
1509#endif
1510 if (GrIsFillInverted(fill)) {
1511 this->drawPaint(paint);
1512 }
1513 return;
1514 }
1515
bsalomon@google.com27847de2011-02-22 20:59:41 +00001516 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001517
bsalomon@google.com289533a2011-10-27 12:34:25 +00001518 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1519
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001520 // An Assumption here is that path renderer would use some form of tweaking
1521 // the src color (either the input alpha or in the frag shader) to implement
1522 // aa. If we have some future driver-mojo path AA that can do the right
1523 // thing WRT to the blend then we'll need some query on the PR.
1524 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001525#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001526 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001527#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001528 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001529 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001530
1531 bool doOSAA = false;
1532 GrPathRenderer* pr = NULL;
1533 if (prAA) {
1534 pr = this->getPathRenderer(path, fill, true);
1535 if (NULL == pr) {
1536 prAA = false;
1537 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1538 pr = this->getPathRenderer(path, fill, false);
1539 }
1540 } else {
1541 pr = this->getPathRenderer(path, fill, false);
1542 }
1543
bsalomon@google.com30085192011-08-19 15:42:31 +00001544 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001545#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001546 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001547#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001548 return;
1549 }
1550
bsalomon@google.com289533a2011-10-27 12:34:25 +00001551 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001552 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001553
bsalomon@google.com289533a2011-10-27 12:34:25 +00001554 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001555 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001556
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001557 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001558 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1559 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001560 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001561 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001562 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001563 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001564 return;
1565 }
1566 }
reed@google.com70c136e2011-06-03 19:51:26 +00001567
reed@google.com07f3ee12011-05-16 17:21:57 +00001568 GrRect pathBounds = path.getBounds();
1569 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001570 if (NULL != translate) {
1571 pathBounds.offset(*translate);
1572 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001573 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001574 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001575 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001576 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001577 return;
1578 }
1579 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001580 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001581 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1582 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001583 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1584 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1585 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001586 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001587 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1588 }
1589 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001590 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001591 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001592 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1593 GrRect rect;
1594 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001595 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1596 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001597 target->drawSimpleRect(rect, NULL, stageMask);
1598 }
1599 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001600 rect.iset(clipIBounds.fLeft, bound.fTop,
1601 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001602 target->drawSimpleRect(rect, NULL, stageMask);
1603 }
1604 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001605 rect.iset(bound.fRight, bound.fTop,
1606 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001607 target->drawSimpleRect(rect, NULL, stageMask);
1608 }
1609 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001610 rect.iset(clipIBounds.fLeft, bound.fBottom,
1611 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001612 target->drawSimpleRect(rect, NULL, stageMask);
1613 }
1614 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001615 return;
1616 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001617 }
1618 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001619}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001620
bsalomon@google.com27847de2011-02-22 20:59:41 +00001621////////////////////////////////////////////////////////////////////////////////
1622
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001623bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001624 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001625}
1626
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001627void GrContext::flush(int flagsBitfield) {
1628 if (kDiscard_FlushBit & flagsBitfield) {
1629 fDrawBuffer->reset();
1630 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001631 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001632 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001633 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001634 fGpu->forceRenderTargetFlush();
1635 }
1636}
1637
1638void GrContext::flushText() {
1639 if (kText_DrawCategory == fLastDrawCategory) {
1640 flushDrawBuffer();
1641 }
1642}
1643
1644void GrContext::flushDrawBuffer() {
1645#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001646 if (fDrawBuffer) {
1647 fDrawBuffer->playback(fGpu);
1648 fDrawBuffer->reset();
1649 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001650#endif
1651}
1652
bsalomon@google.com6f379512011-11-16 20:36:03 +00001653void GrContext::internalWriteTexturePixels(GrTexture* texture,
1654 int left, int top,
1655 int width, int height,
1656 GrPixelConfig config,
1657 const void* buffer,
1658 size_t rowBytes,
1659 uint32_t flags) {
1660 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001661 ASSERT_OWNED_RESOURCE(texture);
1662
bsalomon@google.com6f379512011-11-16 20:36:03 +00001663 if (!(kDontFlush_PixelOpsFlag & flags)) {
1664 this->flush();
1665 }
1666 // TODO: use scratch texture to perform conversion
1667 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1668 GrPixelConfigIsUnpremultiplied(config)) {
1669 return;
1670 }
1671
1672 fGpu->writeTexturePixels(texture, left, top, width, height,
1673 config, buffer, rowBytes);
1674}
1675
1676bool GrContext::internalReadTexturePixels(GrTexture* texture,
1677 int left, int top,
1678 int width, int height,
1679 GrPixelConfig config,
1680 void* buffer,
1681 size_t rowBytes,
1682 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001683 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001684 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001685
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001686 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001687 GrRenderTarget* target = texture->asRenderTarget();
1688 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001689 return this->internalReadRenderTargetPixels(target,
1690 left, top, width, height,
1691 config, buffer, rowBytes,
1692 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001693 } else {
1694 return false;
1695 }
1696}
1697
bsalomon@google.com6f379512011-11-16 20:36:03 +00001698bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1699 int left, int top,
1700 int width, int height,
1701 GrPixelConfig config,
1702 void* buffer,
1703 size_t rowBytes,
1704 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001705 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001706 ASSERT_OWNED_RESOURCE(target);
1707
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001708 if (NULL == target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001709 target = fGpu->getRenderTarget();
1710 if (NULL == target) {
1711 return false;
1712 }
1713 }
1714
1715 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1716 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1717 // not supported at this time.
1718 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1719 !GrPixelConfigIsUnpremultiplied(config)) {
1720 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001721 }
1722
bsalomon@google.com6f379512011-11-16 20:36:03 +00001723 if (!(kDontFlush_PixelOpsFlag & flags)) {
1724 this->flush();
1725 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001726
1727 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001728 bool swapRAndB = NULL != src &&
1729 fGpu->preferredReadPixelsConfig(config) ==
1730 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001731
1732 bool flipY = NULL != src &&
1733 fGpu->readPixelsWillPayForYFlip(target, left, top,
1734 width, height, config,
1735 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001736 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1737 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001738
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001739 if (NULL == src && alphaConversion) {
1740 // we should fallback to cpu conversion here. This could happen when
1741 // we were given an external render target by the client that is not
1742 // also a texture (e.g. FBO 0 in GL)
1743 return false;
1744 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001745 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001746 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001747 if (flipY || swapRAndB || alphaConversion) {
1748 GrAssert(NULL != src);
1749 if (swapRAndB) {
1750 config = GrPixelConfigSwapRAndB(config);
1751 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001752 }
1753 // Make the scratch a render target because we don't have a robust
1754 // readTexturePixels as of yet (it calls this function).
1755 const GrTextureDesc desc = {
1756 kRenderTarget_GrTextureFlagBit,
1757 kNone_GrAALevel,
1758 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001759 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001760 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001761
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001762 // When a full readback is faster than a partial we could always make
1763 // the scratch exactly match the passed rect. However, if we see many
1764 // different size rectangles we will trash our texture cache and pay the
1765 // cost of creating and destroying many textures. So, we only request
1766 // an exact match when the caller is reading an entire RT.
1767 ScratchTexMatch match = kApprox_ScratchTexMatch;
1768 if (0 == left &&
1769 0 == top &&
1770 target->width() == width &&
1771 target->height() == height &&
1772 fGpu->fullReadPixelsIsFasterThanPartial()) {
1773 match = kExact_ScratchTexMatch;
1774 }
1775 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001776 GrTexture* texture = ast.texture();
1777 if (!texture) {
1778 return false;
1779 }
1780 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001781 GrAssert(NULL != target);
1782
1783 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001784 reset_target_state(fGpu);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001785
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001786 fGpu->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001787
bsalomon@google.comc4364992011-11-07 15:54:49 +00001788 GrMatrix matrix;
1789 if (flipY) {
1790 matrix.setTranslate(SK_Scalar1 * left,
1791 SK_Scalar1 * (top + height));
1792 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1793 } else {
1794 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1795 }
1796 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001797 GrSamplerState sampler;
1798 sampler.reset(GrSamplerState::kClamp_WrapMode,
1799 GrSamplerState::kNearest_Filter,
1800 matrix);
1801 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001802 fGpu->setSamplerState(0, sampler);
1803 fGpu->setTexture(0, src);
1804 GrRect rect;
1805 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1806 fGpu->drawSimpleRect(rect, NULL, 0x1);
1807 left = 0;
1808 top = 0;
1809 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001810 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001811 left, top, width, height,
1812 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001813}
1814
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001815void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1816 if (NULL == src || NULL == dst) {
1817 return;
1818 }
1819 ASSERT_OWNED_RESOURCE(src);
1820
1821 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001822 reset_target_state(fGpu);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001823 fGpu->setRenderTarget(dst);
bsalomon@google.com97912912011-12-06 16:30:36 +00001824 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001825 GrSamplerState::kNearest_Filter);
1826 GrMatrix sampleM;
1827 sampleM.setIDiv(src->width(), src->height());
1828 sampler.setMatrix(sampleM);
1829 fGpu->setTexture(0, src);
1830 fGpu->setSamplerState(0, sampler);
1831 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1832 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1833}
1834
bsalomon@google.com6f379512011-11-16 20:36:03 +00001835void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1836 int left, int top,
1837 int width, int height,
1838 GrPixelConfig config,
1839 const void* buffer,
1840 size_t rowBytes,
1841 uint32_t flags) {
1842 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001843 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001844
1845 if (NULL == target) {
1846 target = fGpu->getRenderTarget();
1847 if (NULL == target) {
1848 return;
1849 }
1850 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001851
1852 // TODO: when underlying api has a direct way to do this we should use it
1853 // (e.g. glDrawPixels on desktop GL).
1854
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001855 // If the RT is also a texture and we don't have to do PM/UPM conversion
1856 // then take the texture path, which we expect to be at least as fast or
1857 // faster since it doesn't use an intermediate texture as we do below.
1858
1859#if !GR_MAC_BUILD
1860 // At least some drivers on the Mac get confused when glTexImage2D is called
1861 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1862 // determine what OS versions and/or HW is affected.
1863 if (NULL != target->asTexture() &&
1864 GrPixelConfigIsUnpremultiplied(target->config()) ==
1865 GrPixelConfigIsUnpremultiplied(config)) {
1866
1867 this->internalWriteTexturePixels(target->asTexture(),
1868 left, top, width, height,
1869 config, buffer, rowBytes, flags);
1870 return;
1871 }
1872#endif
1873
1874 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1875 GrPixelConfigSwapRAndB(config);
1876 if (swapRAndB) {
1877 config = GrPixelConfigSwapRAndB(config);
1878 }
1879
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001880 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001881 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001882 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001883 GrAutoScratchTexture ast(this, desc);
1884 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001885 if (NULL == texture) {
1886 return;
1887 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001888 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1889 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001890
bsalomon@google.com27847de2011-02-22 20:59:41 +00001891 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001892 reset_target_state(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001893
1894 GrMatrix matrix;
1895 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1896 fGpu->setViewMatrix(matrix);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001897 fGpu->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001898 fGpu->setTexture(0, texture);
1899
bsalomon@google.com5c638652011-07-18 19:31:59 +00001900 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001901 GrSamplerState sampler;
1902 sampler.reset(GrSamplerState::kClamp_WrapMode,
1903 GrSamplerState::kNearest_Filter,
1904 matrix);
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001905 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001906 fGpu->setSamplerState(0, sampler);
1907
1908 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1909 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001910 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001911 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1912 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001913 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001914 return;
1915 }
1916 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1917 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1918}
1919////////////////////////////////////////////////////////////////////////////////
1920
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001921void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001922
1923 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1924 int s = i + GrPaint::kFirstTextureStage;
1925 target->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001926 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001927 target->setSamplerState(s, paint.getTextureSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001928 }
1929
1930 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1931
1932 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1933 int s = i + GrPaint::kFirstMaskStage;
1934 target->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001935 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001936 target->setSamplerState(s, paint.getMaskSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001937 }
1938
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001939 target->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001940
1941 if (paint.fDither) {
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001942 target->enableState(GrDrawTarget::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001943 } else {
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001944 target->disableState(GrDrawTarget::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001945 }
1946 if (paint.fAntiAlias) {
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001947 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001948 } else {
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001949 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001950 }
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001951 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1952 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001953
1954 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1955 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1956 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001957}
1958
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001959GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001960 DrawCategory category) {
1961 if (category != fLastDrawCategory) {
1962 flushDrawBuffer();
1963 fLastDrawCategory = category;
1964 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001965 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001966 GrDrawTarget* target = fGpu;
1967 switch (category) {
1968 case kText_DrawCategory:
1969#if DEFER_TEXT_RENDERING
1970 target = fDrawBuffer;
1971 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1972#else
1973 target = fGpu;
1974#endif
1975 break;
1976 case kUnbuffered_DrawCategory:
1977 target = fGpu;
1978 break;
1979 case kBuffered_DrawCategory:
1980 target = fDrawBuffer;
1981 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1982 break;
1983 }
1984 return target;
1985}
1986
bsalomon@google.com289533a2011-10-27 12:34:25 +00001987GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1988 GrPathFill fill,
1989 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001990 if (NULL == fPathRendererChain) {
1991 fPathRendererChain =
1992 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1993 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001994 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1995 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001996}
1997
bsalomon@google.com27847de2011-02-22 20:59:41 +00001998////////////////////////////////////////////////////////////////////////////////
1999
bsalomon@google.com27847de2011-02-22 20:59:41 +00002000void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002001 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002002 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002003 fGpu->setRenderTarget(target);
2004}
2005
2006GrRenderTarget* GrContext::getRenderTarget() {
2007 return fGpu->getRenderTarget();
2008}
2009
2010const GrRenderTarget* GrContext::getRenderTarget() const {
2011 return fGpu->getRenderTarget();
2012}
2013
2014const GrMatrix& GrContext::getMatrix() const {
2015 return fGpu->getViewMatrix();
2016}
2017
2018void GrContext::setMatrix(const GrMatrix& m) {
2019 fGpu->setViewMatrix(m);
2020}
2021
2022void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00002023 fGpu->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002024}
2025
2026static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2027 intptr_t mask = 1 << shift;
2028 if (pred) {
2029 bits |= mask;
2030 } else {
2031 bits &= ~mask;
2032 }
2033 return bits;
2034}
2035
2036void GrContext::resetStats() {
2037 fGpu->resetStats();
2038}
2039
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002040const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002041 return fGpu->getStats();
2042}
2043
2044void GrContext::printStats() const {
2045 fGpu->printStats();
2046}
2047
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002048GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002049 fGpu = gpu;
2050 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002051 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002052
bsalomon@google.com30085192011-08-19 15:42:31 +00002053 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002054
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002055 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2056 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002057 fFontCache = new GrFontCache(fGpu);
2058
2059 fLastDrawCategory = kUnbuffered_DrawCategory;
2060
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002061 fDrawBuffer = NULL;
2062 fDrawBufferVBAllocPool = NULL;
2063 fDrawBufferIBAllocPool = NULL;
2064
bsalomon@google.com205d4602011-04-25 12:43:45 +00002065 fAAFillRectIndexBuffer = NULL;
2066 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002067
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002068 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2069 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002070 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2071 }
2072 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002073
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002074 this->setupDrawBuffer();
2075}
2076
2077void GrContext::setupDrawBuffer() {
2078
2079 GrAssert(NULL == fDrawBuffer);
2080 GrAssert(NULL == fDrawBufferVBAllocPool);
2081 GrAssert(NULL == fDrawBufferIBAllocPool);
2082
bsalomon@google.com27847de2011-02-22 20:59:41 +00002083#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002084 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002085 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002086 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2087 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002088 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002089 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002090 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002091 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2092
bsalomon@google.com471d4712011-08-23 15:45:25 +00002093 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2094 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002095 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002096#endif
2097
2098#if BATCH_RECT_TO_RECT
2099 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2100#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002101}
2102
bsalomon@google.com27847de2011-02-22 20:59:41 +00002103GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2104 GrDrawTarget* target;
2105#if DEFER_TEXT_RENDERING
2106 target = prepareToDraw(paint, kText_DrawCategory);
2107#else
2108 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2109#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002110 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002111 return target;
2112}
2113
2114const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2115 return fGpu->getQuadIndexBuffer();
2116}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002117
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002118void GrContext::convolveInX(GrTexture* texture,
2119 const SkRect& rect,
2120 const float* kernel,
2121 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002122 ASSERT_OWNED_RESOURCE(texture);
2123
bsalomon@google.com99621082011-11-15 16:47:16 +00002124 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002125 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2126}
2127
2128void GrContext::convolveInY(GrTexture* texture,
2129 const SkRect& rect,
2130 const float* kernel,
2131 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002132 ASSERT_OWNED_RESOURCE(texture);
2133
bsalomon@google.com99621082011-11-15 16:47:16 +00002134 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002135 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2136}
2137
2138void GrContext::convolve(GrTexture* texture,
2139 const SkRect& rect,
2140 float imageIncrement[2],
2141 const float* kernel,
2142 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002143 ASSERT_OWNED_RESOURCE(texture);
2144
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002145 GrDrawTarget::AutoStateRestore asr(fGpu);
2146 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +00002147 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002148 GrSamplerState::kConvolution_Filter);
2149 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002150 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002151 sampler.setMatrix(sampleM);
2152 fGpu->setSamplerState(0, sampler);
2153 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002154 fGpu->setTexture(0, texture);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002155 fGpu->setColor(0xFFFFFFFF);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002156 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002157 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2158}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002159
2160///////////////////////////////////////////////////////////////////////////////