blob: a792bd11b3b3775ec26700a144399fa603539c2d [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.com0fec61d2011-12-08 15:53:53 +0000220void reset_target_state(GrDrawState* drawState) {
221 drawState->setViewMatrix(GrMatrix::I());
222 drawState->setColorFilter(0, SkXfermode::kDst_Mode);
223 drawState->resetStateFlags();
224 drawState->setEdgeAAData(NULL, 0);
225 drawState->disableStencil();
226 drawState->setAlpha(0xFF);
227 drawState->setBlendFunc(kOne_BlendCoeff,
228 kZero_BlendCoeff);
229 drawState->setFirstCoverageStage(GrDrawState::kNumStages);
230 drawState->setDrawFace(GrDrawState::kBoth_DrawFace);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000231}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000232}
233
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000234GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
235 int width,
236 int height,
237 const GrSamplerState& sampler) {
238 uint32_t v[4];
239 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
240 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000241 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
242 GrResourceCache::kNested_LockType));
243}
244
bsalomon@google.comfb309512011-11-30 14:13:48 +0000245bool GrContext::isTextureInCache(TextureKey key,
246 int width,
247 int height,
248 const GrSamplerState& sampler) const {
249 uint32_t v[4];
250 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
251 GrResourceKey resourceKey(v);
252 return fTextureCache->hasKey(resourceKey);
253}
254
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000255GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000256 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000257 uint32_t v[4];
258 gen_stencil_key_values(sb, v);
259 GrResourceKey resourceKey(v);
260 return fTextureCache->createAndLock(resourceKey, sb);
261}
262
263GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
264 int sampleCnt) {
265 uint32_t v[4];
266 gen_stencil_key_values(width, height, sampleCnt, v);
267 GrResourceKey resourceKey(v);
268 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
269 GrResourceCache::kSingle_LockType);
270 if (NULL != entry) {
271 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
272 return sb;
273 } else {
274 return NULL;
275 }
276}
277
278void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000279 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000280 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000281}
282
283static void stretchImage(void* dst,
284 int dstW,
285 int dstH,
286 void* src,
287 int srcW,
288 int srcH,
289 int bpp) {
290 GrFixed dx = (srcW << 16) / dstW;
291 GrFixed dy = (srcH << 16) / dstH;
292
293 GrFixed y = dy >> 1;
294
295 int dstXLimit = dstW*bpp;
296 for (int j = 0; j < dstH; ++j) {
297 GrFixed x = dx >> 1;
298 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
299 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
300 for (int i = 0; i < dstXLimit; i += bpp) {
301 memcpy((uint8_t*) dstRow + i,
302 (uint8_t*) srcRow + (x>>16)*bpp,
303 bpp);
304 x += dx;
305 }
306 y += dy;
307 }
308}
309
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000310GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000311 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000312 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000313 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000314 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000315
316#if GR_DUMP_TEXTURE_UPLOAD
317 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
318#endif
319
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000320 TextureCacheEntry entry;
321 uint32_t v[4];
322 bool special = gen_texture_key_values(fGpu, sampler, key,
323 desc.fWidth, desc.fHeight, false, v);
324 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000325
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000326 if (special) {
327 TextureCacheEntry clampEntry =
328 findAndLockTexture(key, desc.fWidth, desc.fHeight,
bsalomon@google.com97912912011-12-06 16:30:36 +0000329 GrSamplerState::ClampNearest());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000330
331 if (NULL == clampEntry.texture()) {
332 clampEntry = createAndLockTexture(key,
bsalomon@google.com97912912011-12-06 16:30:36 +0000333 GrSamplerState::ClampNearest(),
bsalomon@google.com27847de2011-02-22 20:59:41 +0000334 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000335 GrAssert(NULL != clampEntry.texture());
336 if (NULL == clampEntry.texture()) {
337 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000338 }
339 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000340 GrTextureDesc rtDesc = desc;
341 rtDesc.fFlags = rtDesc.fFlags |
342 kRenderTarget_GrTextureFlagBit |
343 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000344 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
345 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000346
347 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
348
349 if (NULL != texture) {
350 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com0fec61d2011-12-08 15:53:53 +0000351 reset_target_state(fGpu->drawState());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000352
bsalomon@google.com27847de2011-02-22 20:59:41 +0000353 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000354 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000355
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000356 GrSamplerState::Filter filter;
357 // if filtering is not desired then we want to ensure all
358 // texels in the resampled image are copies of texels from
359 // the original.
360 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
361 filter = GrSamplerState::kNearest_Filter;
362 } else {
363 filter = GrSamplerState::kBilinear_Filter;
364 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000365 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000366 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000367 fGpu->setSamplerState(0, stretchSampler);
368
369 static const GrVertexLayout layout =
370 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
371 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
372
373 if (arg.succeeded()) {
374 GrPoint* verts = (GrPoint*) arg.vertices();
375 verts[0].setIRectFan(0, 0,
376 texture->width(),
377 texture->height(),
378 2*sizeof(GrPoint));
379 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
380 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
381 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000382 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000383 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000384 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000385 } else {
386 // TODO: Our CPU stretch doesn't filter. But we create separate
387 // stretched textures when the sampler state is either filtered or
388 // not. Either implement filtered stretch blit on CPU or just create
389 // one when FBO case fails.
390
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000391 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000392 // no longer need to clamp at min RT size.
393 rtDesc.fWidth = GrNextPow2(desc.fWidth);
394 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000395 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000396 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000397 rtDesc.fWidth *
398 rtDesc.fHeight);
399 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
400 srcData, desc.fWidth, desc.fHeight, bpp);
401
402 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
403
404 GrTexture* texture = fGpu->createTexture(rtDesc,
405 stretchedPixels.get(),
406 stretchedRowBytes);
407 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000408 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000409 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000410 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000411
412 } else {
413 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
414 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000415 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000416 }
417 }
418 return entry;
419}
420
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421namespace {
422inline void gen_scratch_tex_key_values(const GrGpu* gpu,
423 const GrTextureDesc& desc,
424 uint32_t v[4]) {
425 // Instead of a client-provided key of the texture contents
426 // we create a key of from the descriptor.
427 GrContext::TextureKey descKey = desc.fAALevel |
428 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000429 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000430 // this code path isn't friendly to tiling with NPOT restricitons
431 // We just pass ClampNoFilter()
bsalomon@google.com97912912011-12-06 16:30:36 +0000432 gen_texture_key_values(gpu, GrSamplerState::ClampNearest(), descKey,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000433 desc.fWidth, desc.fHeight, true, v);
434}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000435}
436
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000437GrContext::TextureCacheEntry GrContext::lockScratchTexture(
438 const GrTextureDesc& inDesc,
439 ScratchTexMatch match) {
440
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000441 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000442 if (kExact_ScratchTexMatch != match) {
443 // bin by pow2 with a reasonable min
444 static const int MIN_SIZE = 256;
445 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
446 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
447 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000448
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000449 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000450 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
451
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000452 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000453 int origWidth = desc.fWidth;
454 int origHeight = desc.fHeight;
455 bool doubledW = false;
456 bool doubledH = false;
457
458 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000459 uint32_t v[4];
460 gen_scratch_tex_key_values(fGpu, desc, v);
461 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000462 entry = fTextureCache->findAndLock(key,
463 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000464 // if we miss, relax the fit of the flags...
465 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000466 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000467 break;
468 }
469 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
470 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
471 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
472 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
473 } else if (!doubledW) {
474 desc.fFlags = inDesc.fFlags;
475 desc.fWidth *= 2;
476 doubledW = true;
477 } else if (!doubledH) {
478 desc.fFlags = inDesc.fFlags;
479 desc.fWidth = origWidth;
480 desc.fHeight *= 2;
481 doubledH = true;
482 } else {
483 break;
484 }
485
486 } while (true);
487
488 if (NULL == entry) {
489 desc.fFlags = inDesc.fFlags;
490 desc.fWidth = origWidth;
491 desc.fHeight = origHeight;
492 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
493 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000494 uint32_t v[4];
495 gen_scratch_tex_key_values(fGpu, desc, v);
496 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000497 entry = fTextureCache->createAndLock(key, texture);
498 }
499 }
500
501 // If the caller gives us the same desc/sampler twice we don't want
502 // to return the same texture the second time (unless it was previously
503 // released). So we detach the entry from the cache and reattach at release.
504 if (NULL != entry) {
505 fTextureCache->detach(entry);
506 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000507 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000508}
509
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000510void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000511 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000512 // If this is a scratch texture we detached it from the cache
513 // while it was locked (to avoid two callers simultaneously getting
514 // the same texture).
515 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
516 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000517 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000519 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000520}
521
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000522GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000523 void* srcData,
524 size_t rowBytes) {
525 return fGpu->createTexture(desc, srcData, rowBytes);
526}
527
528void GrContext::getTextureCacheLimits(int* maxTextures,
529 size_t* maxTextureBytes) const {
530 fTextureCache->getLimits(maxTextures, maxTextureBytes);
531}
532
533void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
534 fTextureCache->setLimits(maxTextures, maxTextureBytes);
535}
536
bsalomon@google.com91958362011-06-13 17:58:13 +0000537int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000538 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000539}
540
541int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000542 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000543}
544
545///////////////////////////////////////////////////////////////////////////////
546
bsalomon@google.come269f212011-11-07 13:29:52 +0000547GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
548 return fGpu->createPlatformTexture(desc);
549}
550
551GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
552 return fGpu->createPlatformRenderTarget(desc);
553}
554
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000555GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
556 // validate flags here so that GrGpu subclasses don't have to check
557 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
558 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000559 return NULL;
560 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000561 if (desc.fSampleCnt &&
562 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000563 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000564 }
565 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
566 desc.fSampleCnt &&
567 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
568 return NULL;
569 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000570 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000571}
572
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000573///////////////////////////////////////////////////////////////////////////////
574
bsalomon@google.com27847de2011-02-22 20:59:41 +0000575bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000576 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000577 const GrDrawTarget::Caps& caps = fGpu->getCaps();
578 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000579 return false;
580 }
581
bsalomon@google.com27847de2011-02-22 20:59:41 +0000582 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
583
584 if (!isPow2) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000585 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
586 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000587 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588 return false;
589 }
590 }
591 return true;
592}
593
594////////////////////////////////////////////////////////////////////////////////
595
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000596const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
597
bsalomon@google.com27847de2011-02-22 20:59:41 +0000598void GrContext::setClip(const GrClip& clip) {
599 fGpu->setClip(clip);
bsalomon@google.com0fec61d2011-12-08 15:53:53 +0000600 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000601}
602
603void GrContext::setClip(const GrIRect& rect) {
604 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000605 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000606 fGpu->setClip(clip);
607}
608
609////////////////////////////////////////////////////////////////////////////////
610
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000611void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000612 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000613 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000614}
615
616void GrContext::drawPaint(const GrPaint& paint) {
617 // set rect to be big enough to fill the space, but not super-huge, so we
618 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000619 GrRect r;
620 r.setLTRB(0, 0,
621 GrIntToScalar(getRenderTarget()->width()),
622 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000623 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000624 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000625 SkTLazy<GrPaint> tmpPaint;
626 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000627 // We attempt to map r by the inverse matrix and draw that. mapRect will
628 // map the four corners and bound them with a new rect. This will not
629 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000630 if (!this->getMatrix().hasPerspective()) {
631 if (!fGpu->getViewInverse(&inverse)) {
632 GrPrintf("Could not invert matrix");
633 return;
634 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000635 inverse.mapRect(&r);
636 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000637 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
638 if (!fGpu->getViewInverse(&inverse)) {
639 GrPrintf("Could not invert matrix");
640 return;
641 }
642 tmpPaint.set(paint);
643 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
644 p = tmpPaint.get();
645 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000646 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000647 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000648 // by definition this fills the entire clip, no need for AA
649 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000650 if (!tmpPaint.isValid()) {
651 tmpPaint.set(paint);
652 p = tmpPaint.get();
653 }
654 GrAssert(p == tmpPaint.get());
655 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000656 }
657 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000658}
659
bsalomon@google.com205d4602011-04-25 12:43:45 +0000660////////////////////////////////////////////////////////////////////////////////
661
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000662namespace {
663inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
664 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
665}
666}
667
bsalomon@google.com91958362011-06-13 17:58:13 +0000668struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000669 enum Downsample {
670 k4x4TwoPass_Downsample,
671 k4x4SinglePass_Downsample,
672 kFSAA_Downsample
673 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000674 int fTileSizeX;
675 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000676 int fTileCountX;
677 int fTileCountY;
678 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000679 GrAutoScratchTexture fOffscreen0;
680 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000681 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000682 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000683};
684
bsalomon@google.com471d4712011-08-23 15:45:25 +0000685bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000686 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000687#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000688 return false;
689#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000690 // Line primitves are always rasterized as 1 pixel wide.
691 // Super-sampling would make them too thin but MSAA would be OK.
692 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000693 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000694 return false;
695 }
696 if (target->getRenderTarget()->isMultisampled()) {
697 return false;
698 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000699 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000700#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000701 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000702#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000703 return false;
704 }
705 return true;
706#endif
707}
708
bsalomon@google.com91958362011-06-13 17:58:13 +0000709bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000710 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000711 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000712 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000713 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000714
715 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000716
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000717 GrAssert(NULL == record->fOffscreen0.texture());
718 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000719 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000720
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000721 int boundW = boundRect.width();
722 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000723
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000724 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000725
726 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
727 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
728
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729 if (requireStencil) {
730 desc.fFlags = kRenderTarget_GrTextureFlagBit;
731 } else {
732 desc.fFlags = kRenderTarget_GrTextureFlagBit |
733 kNoStencil_GrTextureFlagBit;
734 }
735
bsalomon@google.comc4364992011-11-07 15:54:49 +0000736 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000737
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000738 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000739 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000740 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000741 desc.fAALevel = kMed_GrAALevel;
742 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000743 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000744 OffscreenRecord::k4x4SinglePass_Downsample :
745 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000746 record->fScale = OFFSCREEN_SSAA_SCALE;
747 // both downsample paths assume this
748 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000749 desc.fAALevel = kNone_GrAALevel;
750 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000751
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000752 desc.fWidth *= record->fScale;
753 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000754 record->fOffscreen0.set(this, desc);
755 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000756 return false;
757 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000758 // the approximate lookup might have given us some slop space, might as well
759 // use it when computing the tiles size.
760 // these are scale values, will adjust after considering
761 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000762 record->fTileSizeX = record->fOffscreen0.texture()->width();
763 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000764
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000765 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000766 desc.fWidth /= 2;
767 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000768 record->fOffscreen1.set(this, desc);
769 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000770 return false;
771 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000772 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000773 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000774 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000775 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000776 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000777 record->fTileSizeX /= record->fScale;
778 record->fTileSizeY /= record->fScale;
779
780 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
781 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
782
tomhudson@google.com237a4612011-07-19 15:44:00 +0000783 record->fClip = target->getClip();
784
bsalomon@google.com91958362011-06-13 17:58:13 +0000785 target->saveCurrentDrawState(&record->fSavedState);
786 return true;
787}
788
789void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
790 const GrIRect& boundRect,
791 int tileX, int tileY,
792 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000793
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000794 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000796
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000797 GrPaint tempPaint;
798 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000799 this->setPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000800 target->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000801#if PREFER_MSAA_OFFSCREEN_AA
802 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
803#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000804
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000805 int left = boundRect.fLeft + tileX * record->fTileSizeX;
806 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com0fec61d2011-12-08 15:53:53 +0000807 GrDrawState* drawState = target->drawState();
808 drawState->viewMatrix()->postTranslate(-left * GR_Scalar1,
809 -top * GR_Scalar1);
810 drawState->viewMatrix()->postScale(record->fScale * GR_Scalar1,
811 record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000812
bsalomon@google.com91958362011-06-13 17:58:13 +0000813 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000814 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000815 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000816 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000817 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
818 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000819 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000820#if 0
821 // visualize tile boundaries by setting edges of offscreen to white
822 // and interior to tranparent. black.
823 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000824
bsalomon@google.com91958362011-06-13 17:58:13 +0000825 static const int gOffset = 2;
826 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
827 record->fScale * w - gOffset,
828 record->fScale * h - gOffset);
829 target->clear(&clear2, 0x0);
830#else
831 target->clear(&clear, 0x0);
832#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000833}
834
bsalomon@google.com91958362011-06-13 17:58:13 +0000835void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000836 const GrPaint& paint,
837 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000838 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000839 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000840 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000841 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000842 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000843 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000844 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
845 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000846 tileRect.fRight = (tileX == record->fTileCountX-1) ?
847 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000848 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000849 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
850 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000851 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000852
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000853 GrSamplerState::Filter filter;
854 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
855 filter = GrSamplerState::k4x4Downsample_Filter;
856 } else {
857 filter = GrSamplerState::kBilinear_Filter;
858 }
859
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000860 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +0000861 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000862
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000863 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000864 int scale;
865
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000866 enum {
867 kOffscreenStage = GrPaint::kTotalStages,
868 };
869
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000870 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000871 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000873 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000874
875 // Do 2x2 downsample from first to second
876 target->setTexture(kOffscreenStage, src);
877 target->setRenderTarget(dst);
878 target->setViewMatrix(GrMatrix::I());
879 sampleM.setScale(scale * GR_Scalar1 / src->width(),
880 scale * GR_Scalar1 / src->height());
881 sampler.setMatrix(sampleM);
882 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000883 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
884 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000885 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
886
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000887 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000888 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000889 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000890 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000891 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000892 } else {
893 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
894 record->fDownsample);
895 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000896 }
897
bsalomon@google.com91958362011-06-13 17:58:13 +0000898 // setup for draw back to main RT, we use the original
899 // draw state setup by the caller plus an additional coverage
900 // stage to handle the AA resolve. Also, we use an identity
901 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000902 int stageMask = paint.getActiveStageMask();
903
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000904 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000905 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000906
907 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000908 GrMatrix invVM;
909 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000910 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000911 }
912 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000913 // This is important when tiling, otherwise second tile's
914 // pass 1 view matrix will be incorrect.
915 GrDrawTarget::AutoViewMatrixRestore avmr(target);
916
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000917 target->setViewMatrix(GrMatrix::I());
918
919 target->setTexture(kOffscreenStage, src);
920 sampleM.setScale(scale * GR_Scalar1 / src->width(),
921 scale * GR_Scalar1 / src->height());
922 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000923 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
924 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000925 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000926 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000927
reed@google.com20efde72011-05-09 17:00:02 +0000928 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000929 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000930 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000931 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000932}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000933
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000934void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
935 GrPathRenderer* pr,
936 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000937 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000938}
939
940////////////////////////////////////////////////////////////////////////////////
941
bsalomon@google.com27847de2011-02-22 20:59:41 +0000942/* create a triangle strip that strokes the specified triangle. There are 8
943 unique vertices, but we repreat the last 2 to close up. Alternatively we
944 could use an indices array, and then only send 8 verts, but not sure that
945 would be faster.
946 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000947static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000948 GrScalar width) {
949 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000950 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000951
952 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
953 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
954 verts[2].set(rect.fRight - rad, rect.fTop + rad);
955 verts[3].set(rect.fRight + rad, rect.fTop - rad);
956 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
957 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
958 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
959 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
960 verts[8] = verts[0];
961 verts[9] = verts[1];
962}
963
bsalomon@google.com205d4602011-04-25 12:43:45 +0000964static void setInsetFan(GrPoint* pts, size_t stride,
965 const GrRect& r, GrScalar dx, GrScalar dy) {
966 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
967}
968
969static const uint16_t gFillAARectIdx[] = {
970 0, 1, 5, 5, 4, 0,
971 1, 2, 6, 6, 5, 1,
972 2, 3, 7, 7, 6, 2,
973 3, 0, 4, 4, 7, 3,
974 4, 5, 6, 6, 7, 4,
975};
976
977int GrContext::aaFillRectIndexCount() const {
978 return GR_ARRAY_COUNT(gFillAARectIdx);
979}
980
981GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
982 if (NULL == fAAFillRectIndexBuffer) {
983 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
984 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000985 if (NULL != fAAFillRectIndexBuffer) {
986 #if GR_DEBUG
987 bool updated =
988 #endif
989 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
990 sizeof(gFillAARectIdx));
991 GR_DEBUGASSERT(updated);
992 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000993 }
994 return fAAFillRectIndexBuffer;
995}
996
997static const uint16_t gStrokeAARectIdx[] = {
998 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
999 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1000 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1001 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1002
1003 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1004 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1005 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1006 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1007
1008 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1009 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1010 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1011 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1012};
1013
1014int GrContext::aaStrokeRectIndexCount() const {
1015 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1016}
1017
1018GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1019 if (NULL == fAAStrokeRectIndexBuffer) {
1020 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1021 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001022 if (NULL != fAAStrokeRectIndexBuffer) {
1023 #if GR_DEBUG
1024 bool updated =
1025 #endif
1026 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1027 sizeof(gStrokeAARectIdx));
1028 GR_DEBUGASSERT(updated);
1029 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001030 }
1031 return fAAStrokeRectIndexBuffer;
1032}
1033
bsalomon@google.coma3108262011-10-10 14:08:47 +00001034static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1035 bool useCoverage) {
1036 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001037 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001038 if (NULL != target->getTexture(s)) {
1039 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1040 }
1041 }
1042 if (useCoverage) {
1043 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1044 } else {
1045 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1046 }
1047 return layout;
1048}
1049
bsalomon@google.com205d4602011-04-25 12:43:45 +00001050void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001051 const GrRect& devRect,
1052 bool useVertexCoverage) {
1053 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001054
1055 size_t vsize = GrDrawTarget::VertexSize(layout);
1056
1057 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001058 if (!geo.succeeded()) {
1059 GrPrintf("Failed to get space for vertices!\n");
1060 return;
1061 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001062 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1063 if (NULL == indexBuffer) {
1064 GrPrintf("Failed to create index buffer!\n");
1065 return;
1066 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001067
1068 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1069
1070 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1071 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1072
1073 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1074 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1075
1076 verts += sizeof(GrPoint);
1077 for (int i = 0; i < 4; ++i) {
1078 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1079 }
1080
bsalomon@google.coma3108262011-10-10 14:08:47 +00001081 GrColor innerColor;
1082 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001083 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001084 } else {
1085 innerColor = target->getColor();
1086 }
1087
bsalomon@google.com205d4602011-04-25 12:43:45 +00001088 verts += 4 * vsize;
1089 for (int i = 0; i < 4; ++i) {
1090 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1091 }
1092
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001093 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001094
1095 target->drawIndexed(kTriangles_PrimitiveType, 0,
1096 0, 8, this->aaFillRectIndexCount());
1097}
1098
bsalomon@google.coma3108262011-10-10 14:08:47 +00001099void GrContext::strokeAARect(GrDrawTarget* target,
1100 const GrRect& devRect,
1101 const GrVec& devStrokeSize,
1102 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001103 const GrScalar& dx = devStrokeSize.fX;
1104 const GrScalar& dy = devStrokeSize.fY;
1105 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1106 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1107
bsalomon@google.com205d4602011-04-25 12:43:45 +00001108 GrScalar spare;
1109 {
1110 GrScalar w = devRect.width() - dx;
1111 GrScalar h = devRect.height() - dy;
1112 spare = GrMin(w, h);
1113 }
1114
1115 if (spare <= 0) {
1116 GrRect r(devRect);
1117 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001118 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001119 return;
1120 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001121 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001122 size_t vsize = GrDrawTarget::VertexSize(layout);
1123
1124 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001125 if (!geo.succeeded()) {
1126 GrPrintf("Failed to get space for vertices!\n");
1127 return;
1128 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001129 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1130 if (NULL == indexBuffer) {
1131 GrPrintf("Failed to create index buffer!\n");
1132 return;
1133 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001134
1135 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1136
1137 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1138 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1139 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1140 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1141
1142 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1143 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1144 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1145 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1146
1147 verts += sizeof(GrPoint);
1148 for (int i = 0; i < 4; ++i) {
1149 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1150 }
1151
bsalomon@google.coma3108262011-10-10 14:08:47 +00001152 GrColor innerColor;
1153 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001154 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001155 } else {
1156 innerColor = target->getColor();
1157 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001158 verts += 4 * vsize;
1159 for (int i = 0; i < 8; ++i) {
1160 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1161 }
1162
1163 verts += 8 * vsize;
1164 for (int i = 0; i < 8; ++i) {
1165 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1166 }
1167
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001168 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001169 target->drawIndexed(kTriangles_PrimitiveType,
1170 0, 0, 16, aaStrokeRectIndexCount());
1171}
1172
reed@google.com20efde72011-05-09 17:00:02 +00001173/**
1174 * Returns true if the rects edges are integer-aligned.
1175 */
1176static bool isIRect(const GrRect& r) {
1177 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1178 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1179}
1180
bsalomon@google.com205d4602011-04-25 12:43:45 +00001181static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001182 const GrRect& rect,
1183 GrScalar width,
1184 const GrMatrix* matrix,
1185 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001186 GrRect* devRect,
1187 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001188 // we use a simple alpha ramp to do aa on axis-aligned rects
1189 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001190 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001191
bsalomon@google.coma3108262011-10-10 14:08:47 +00001192 // we are keeping around the "tweak the alpha" trick because
1193 // it is our only hope for the fixed-pipe implementation.
1194 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001195 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001196 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001197 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001198 if (target->getCaps().fSupportPerVertexCoverage) {
1199 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001200#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001201 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001202#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001203 return false;
1204 } else {
1205 *useVertexCoverage = true;
1206 }
1207 } else {
1208 GrPrintf("Rect AA dropped because no support for coverage.\n");
1209 return false;
1210 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001211 }
1212
1213 if (target->getRenderTarget()->isMultisampled()) {
1214 return false;
1215 }
1216
bsalomon@google.com471d4712011-08-23 15:45:25 +00001217 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001218 return false;
1219 }
1220
1221 if (!target->getViewMatrix().preservesAxisAlignment()) {
1222 return false;
1223 }
1224
1225 if (NULL != matrix &&
1226 !matrix->preservesAxisAlignment()) {
1227 return false;
1228 }
1229
1230 *combinedMatrix = target->getViewMatrix();
1231 if (NULL != matrix) {
1232 combinedMatrix->preConcat(*matrix);
1233 GrAssert(combinedMatrix->preservesAxisAlignment());
1234 }
1235
1236 combinedMatrix->mapRect(devRect, rect);
1237 devRect->sort();
1238
1239 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001240 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001241 } else {
1242 return true;
1243 }
1244}
1245
bsalomon@google.com27847de2011-02-22 20:59:41 +00001246void GrContext::drawRect(const GrPaint& paint,
1247 const GrRect& rect,
1248 GrScalar width,
1249 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001250 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001251
1252 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001253 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001254
bsalomon@google.com205d4602011-04-25 12:43:45 +00001255 GrRect devRect = rect;
1256 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001257 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001258 bool needAA = paint.fAntiAlias &&
1259 !this->getRenderTarget()->isMultisampled();
1260 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1261 &combinedMatrix, &devRect,
1262 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001263
1264 if (doAA) {
1265 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001266 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001267 GrMatrix inv;
1268 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001269 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001270 }
1271 }
1272 target->setViewMatrix(GrMatrix::I());
1273 if (width >= 0) {
1274 GrVec strokeSize;;
1275 if (width > 0) {
1276 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001277 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001278 strokeSize.setAbs(strokeSize);
1279 } else {
1280 strokeSize.set(GR_Scalar1, GR_Scalar1);
1281 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001282 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001283 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001284 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001285 }
1286 return;
1287 }
1288
bsalomon@google.com27847de2011-02-22 20:59:41 +00001289 if (width >= 0) {
1290 // TODO: consider making static vertex buffers for these cases.
1291 // Hairline could be done by just adding closing vertex to
1292 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001293 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1294
bsalomon@google.com27847de2011-02-22 20:59:41 +00001295 static const int worstCaseVertCount = 10;
1296 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1297
1298 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001299 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001300 return;
1301 }
1302
1303 GrPrimitiveType primType;
1304 int vertCount;
1305 GrPoint* vertex = geo.positions();
1306
1307 if (width > 0) {
1308 vertCount = 10;
1309 primType = kTriangleStrip_PrimitiveType;
1310 setStrokeRectStrip(vertex, rect, width);
1311 } else {
1312 // hairline
1313 vertCount = 5;
1314 primType = kLineStrip_PrimitiveType;
1315 vertex[0].set(rect.fLeft, rect.fTop);
1316 vertex[1].set(rect.fRight, rect.fTop);
1317 vertex[2].set(rect.fRight, rect.fBottom);
1318 vertex[3].set(rect.fLeft, rect.fBottom);
1319 vertex[4].set(rect.fLeft, rect.fTop);
1320 }
1321
1322 GrDrawTarget::AutoViewMatrixRestore avmr;
1323 if (NULL != matrix) {
1324 avmr.set(target);
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001325 target->viewMatrix()->preConcat(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001326 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327 }
1328
1329 target->drawNonIndexed(primType, 0, vertCount);
1330 } else {
1331 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001332 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001333 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1334 if (NULL == sqVB) {
1335 GrPrintf("Failed to create static rect vb.\n");
1336 return;
1337 }
1338 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001339 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1340 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001341 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001342 0, rect.height(), rect.fTop,
1343 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001344
1345 if (NULL != matrix) {
1346 m.postConcat(*matrix);
1347 }
1348
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001349 target->viewMatrix()->preConcat(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001350 target->preConcatSamplerMatrices(stageMask, m);
1351
bsalomon@google.com27847de2011-02-22 20:59:41 +00001352 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1353 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001354 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001355 #endif
1356 }
1357}
1358
1359void GrContext::drawRectToRect(const GrPaint& paint,
1360 const GrRect& dstRect,
1361 const GrRect& srcRect,
1362 const GrMatrix* dstMatrix,
1363 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001364 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001365
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001366 // srcRect refers to paint's first texture
1367 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001368 drawRect(paint, dstRect, -1, dstMatrix);
1369 return;
1370 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001371
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1373
1374#if GR_STATIC_RECT_VB
1375 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001376 GrDrawState* drawState = target->drawState();
1377
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001378 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001379 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1380
1381 GrMatrix m;
1382
1383 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1384 0, dstRect.height(), dstRect.fTop,
1385 0, 0, GrMatrix::I()[8]);
1386 if (NULL != dstMatrix) {
1387 m.postConcat(*dstMatrix);
1388 }
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001389 drawState->viewMatrix()->preConcat(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001390
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001391 // srcRect refers to first stage
1392 int otherStageMask = paint.getActiveStageMask() &
1393 (~(1 << GrPaint::kFirstTextureStage));
1394 if (otherStageMask) {
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001395 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001396 }
1397
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1399 0, srcRect.height(), srcRect.fTop,
1400 0, 0, GrMatrix::I()[8]);
1401 if (NULL != srcMatrix) {
1402 m.postConcat(*srcMatrix);
1403 }
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001404 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001405
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001406 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1407 if (NULL == sqVB) {
1408 GrPrintf("Failed to create static rect vb.\n");
1409 return;
1410 }
1411 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001412 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1413#else
1414
1415 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001416#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001417 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001418#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001419 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1420#endif
1421
tomhudson@google.com93813632011-10-27 20:21:16 +00001422 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1423 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001424 srcRects[0] = &srcRect;
1425 srcMatrices[0] = srcMatrix;
1426
1427 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1428#endif
1429}
1430
1431void GrContext::drawVertices(const GrPaint& paint,
1432 GrPrimitiveType primitiveType,
1433 int vertexCount,
1434 const GrPoint positions[],
1435 const GrPoint texCoords[],
1436 const GrColor colors[],
1437 const uint16_t indices[],
1438 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001439 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001440
1441 GrDrawTarget::AutoReleaseGeometry geo;
1442
1443 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1444
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001445 bool hasTexCoords[GrPaint::kTotalStages] = {
1446 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1447 0 // remaining stages use positions
1448 };
1449
1450 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001451
1452 if (NULL != colors) {
1453 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001454 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001455 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001456
1457 if (sizeof(GrPoint) != vertexSize) {
1458 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001459 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460 return;
1461 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001462 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001464 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1465 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001466 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001467 NULL,
1468 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469 void* curVertex = geo.vertices();
1470
1471 for (int i = 0; i < vertexCount; ++i) {
1472 *((GrPoint*)curVertex) = positions[i];
1473
1474 if (texOffsets[0] > 0) {
1475 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1476 }
1477 if (colorOffset > 0) {
1478 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1479 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001480 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001481 }
1482 } else {
1483 target->setVertexSourceToArray(layout, positions, vertexCount);
1484 }
1485
bsalomon@google.com91958362011-06-13 17:58:13 +00001486 // we don't currently apply offscreen AA to this path. Need improved
1487 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001488
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001489 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001490 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001491 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001492 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001493 target->drawNonIndexed(primitiveType, 0, vertexCount);
1494 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001495}
1496
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001497///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498
reed@google.com07f3ee12011-05-16 17:21:57 +00001499void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1500 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001501
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001502 if (path.isEmpty()) {
1503#if GR_DEBUG
1504 GrPrintf("Empty path should have been caught by canvas.\n");
1505#endif
1506 if (GrIsFillInverted(fill)) {
1507 this->drawPaint(paint);
1508 }
1509 return;
1510 }
1511
bsalomon@google.com27847de2011-02-22 20:59:41 +00001512 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001513
bsalomon@google.com289533a2011-10-27 12:34:25 +00001514 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1515
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001516 // An Assumption here is that path renderer would use some form of tweaking
1517 // the src color (either the input alpha or in the frag shader) to implement
1518 // aa. If we have some future driver-mojo path AA that can do the right
1519 // thing WRT to the blend then we'll need some query on the PR.
1520 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001521#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001522 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001523#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001524 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001525 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001526
1527 bool doOSAA = false;
1528 GrPathRenderer* pr = NULL;
1529 if (prAA) {
1530 pr = this->getPathRenderer(path, fill, true);
1531 if (NULL == pr) {
1532 prAA = false;
1533 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1534 pr = this->getPathRenderer(path, fill, false);
1535 }
1536 } else {
1537 pr = this->getPathRenderer(path, fill, false);
1538 }
1539
bsalomon@google.com30085192011-08-19 15:42:31 +00001540 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001541#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001542 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001543#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001544 return;
1545 }
1546
bsalomon@google.com289533a2011-10-27 12:34:25 +00001547 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001548 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001549
bsalomon@google.com289533a2011-10-27 12:34:25 +00001550 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001551 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001552
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001553 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001554 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1555 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001556 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001557 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001558 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001559 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001560 return;
1561 }
1562 }
reed@google.com70c136e2011-06-03 19:51:26 +00001563
reed@google.com07f3ee12011-05-16 17:21:57 +00001564 GrRect pathBounds = path.getBounds();
1565 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001566 if (NULL != translate) {
1567 pathBounds.offset(*translate);
1568 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001569 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001570 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001571 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001572 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001573 return;
1574 }
1575 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001576 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001577 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1578 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001579 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1580 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1581 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001582 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001583 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1584 }
1585 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001586 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001587 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001588 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1589 GrRect rect;
1590 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001591 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1592 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001593 target->drawSimpleRect(rect, NULL, stageMask);
1594 }
1595 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001596 rect.iset(clipIBounds.fLeft, bound.fTop,
1597 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001598 target->drawSimpleRect(rect, NULL, stageMask);
1599 }
1600 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001601 rect.iset(bound.fRight, bound.fTop,
1602 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001603 target->drawSimpleRect(rect, NULL, stageMask);
1604 }
1605 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001606 rect.iset(clipIBounds.fLeft, bound.fBottom,
1607 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001608 target->drawSimpleRect(rect, NULL, stageMask);
1609 }
1610 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001611 return;
1612 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001613 }
1614 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001615}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001616
bsalomon@google.com27847de2011-02-22 20:59:41 +00001617////////////////////////////////////////////////////////////////////////////////
1618
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001619bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001620 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001621}
1622
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001623void GrContext::flush(int flagsBitfield) {
1624 if (kDiscard_FlushBit & flagsBitfield) {
1625 fDrawBuffer->reset();
1626 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001627 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001628 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001629 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001630 fGpu->forceRenderTargetFlush();
1631 }
1632}
1633
1634void GrContext::flushText() {
1635 if (kText_DrawCategory == fLastDrawCategory) {
1636 flushDrawBuffer();
1637 }
1638}
1639
1640void GrContext::flushDrawBuffer() {
1641#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001642 if (fDrawBuffer) {
1643 fDrawBuffer->playback(fGpu);
1644 fDrawBuffer->reset();
1645 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001646#endif
1647}
1648
bsalomon@google.com6f379512011-11-16 20:36:03 +00001649void GrContext::internalWriteTexturePixels(GrTexture* texture,
1650 int left, int top,
1651 int width, int height,
1652 GrPixelConfig config,
1653 const void* buffer,
1654 size_t rowBytes,
1655 uint32_t flags) {
1656 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001657 ASSERT_OWNED_RESOURCE(texture);
1658
bsalomon@google.com6f379512011-11-16 20:36:03 +00001659 if (!(kDontFlush_PixelOpsFlag & flags)) {
1660 this->flush();
1661 }
1662 // TODO: use scratch texture to perform conversion
1663 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1664 GrPixelConfigIsUnpremultiplied(config)) {
1665 return;
1666 }
1667
1668 fGpu->writeTexturePixels(texture, left, top, width, height,
1669 config, buffer, rowBytes);
1670}
1671
1672bool GrContext::internalReadTexturePixels(GrTexture* texture,
1673 int left, int top,
1674 int width, int height,
1675 GrPixelConfig config,
1676 void* buffer,
1677 size_t rowBytes,
1678 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001679 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001680 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001681
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001682 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001683 GrRenderTarget* target = texture->asRenderTarget();
1684 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001685 return this->internalReadRenderTargetPixels(target,
1686 left, top, width, height,
1687 config, buffer, rowBytes,
1688 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001689 } else {
1690 return false;
1691 }
1692}
1693
bsalomon@google.com6f379512011-11-16 20:36:03 +00001694bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1695 int left, int top,
1696 int width, int height,
1697 GrPixelConfig config,
1698 void* buffer,
1699 size_t rowBytes,
1700 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001701 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001702 ASSERT_OWNED_RESOURCE(target);
1703
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001704 if (NULL == target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001705 target = fGpu->getRenderTarget();
1706 if (NULL == target) {
1707 return false;
1708 }
1709 }
1710
1711 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1712 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1713 // not supported at this time.
1714 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1715 !GrPixelConfigIsUnpremultiplied(config)) {
1716 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001717 }
1718
bsalomon@google.com6f379512011-11-16 20:36:03 +00001719 if (!(kDontFlush_PixelOpsFlag & flags)) {
1720 this->flush();
1721 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001722
1723 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001724 bool swapRAndB = NULL != src &&
1725 fGpu->preferredReadPixelsConfig(config) ==
1726 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001727
1728 bool flipY = NULL != src &&
1729 fGpu->readPixelsWillPayForYFlip(target, left, top,
1730 width, height, config,
1731 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001732 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1733 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001734
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001735 if (NULL == src && alphaConversion) {
1736 // we should fallback to cpu conversion here. This could happen when
1737 // we were given an external render target by the client that is not
1738 // also a texture (e.g. FBO 0 in GL)
1739 return false;
1740 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001741 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001742 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001743 if (flipY || swapRAndB || alphaConversion) {
1744 GrAssert(NULL != src);
1745 if (swapRAndB) {
1746 config = GrPixelConfigSwapRAndB(config);
1747 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001748 }
1749 // Make the scratch a render target because we don't have a robust
1750 // readTexturePixels as of yet (it calls this function).
1751 const GrTextureDesc desc = {
1752 kRenderTarget_GrTextureFlagBit,
1753 kNone_GrAALevel,
1754 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001755 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001756 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001757
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001758 // When a full readback is faster than a partial we could always make
1759 // the scratch exactly match the passed rect. However, if we see many
1760 // different size rectangles we will trash our texture cache and pay the
1761 // cost of creating and destroying many textures. So, we only request
1762 // an exact match when the caller is reading an entire RT.
1763 ScratchTexMatch match = kApprox_ScratchTexMatch;
1764 if (0 == left &&
1765 0 == top &&
1766 target->width() == width &&
1767 target->height() == height &&
1768 fGpu->fullReadPixelsIsFasterThanPartial()) {
1769 match = kExact_ScratchTexMatch;
1770 }
1771 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001772 GrTexture* texture = ast.texture();
1773 if (!texture) {
1774 return false;
1775 }
1776 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001777 GrAssert(NULL != target);
1778
1779 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001780 reset_target_state(fGpu->drawState());
bsalomon@google.comc4364992011-11-07 15:54:49 +00001781
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001782 fGpu->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001783
bsalomon@google.comc4364992011-11-07 15:54:49 +00001784 GrMatrix matrix;
1785 if (flipY) {
1786 matrix.setTranslate(SK_Scalar1 * left,
1787 SK_Scalar1 * (top + height));
1788 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1789 } else {
1790 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1791 }
1792 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001793 GrSamplerState sampler;
1794 sampler.reset(GrSamplerState::kClamp_WrapMode,
1795 GrSamplerState::kNearest_Filter,
1796 matrix);
1797 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001798 fGpu->setSamplerState(0, sampler);
1799 fGpu->setTexture(0, src);
1800 GrRect rect;
1801 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1802 fGpu->drawSimpleRect(rect, NULL, 0x1);
1803 left = 0;
1804 top = 0;
1805 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001806 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001807 left, top, width, height,
1808 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001809}
1810
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001811void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1812 if (NULL == src || NULL == dst) {
1813 return;
1814 }
1815 ASSERT_OWNED_RESOURCE(src);
1816
1817 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001818 reset_target_state(fGpu->drawState());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001819 fGpu->setRenderTarget(dst);
bsalomon@google.com97912912011-12-06 16:30:36 +00001820 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001821 GrSamplerState::kNearest_Filter);
1822 GrMatrix sampleM;
1823 sampleM.setIDiv(src->width(), src->height());
1824 sampler.setMatrix(sampleM);
1825 fGpu->setTexture(0, src);
1826 fGpu->setSamplerState(0, sampler);
1827 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1828 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1829}
1830
bsalomon@google.com6f379512011-11-16 20:36:03 +00001831void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1832 int left, int top,
1833 int width, int height,
1834 GrPixelConfig config,
1835 const void* buffer,
1836 size_t rowBytes,
1837 uint32_t flags) {
1838 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001839 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001840
1841 if (NULL == target) {
1842 target = fGpu->getRenderTarget();
1843 if (NULL == target) {
1844 return;
1845 }
1846 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001847
1848 // TODO: when underlying api has a direct way to do this we should use it
1849 // (e.g. glDrawPixels on desktop GL).
1850
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001851 // If the RT is also a texture and we don't have to do PM/UPM conversion
1852 // then take the texture path, which we expect to be at least as fast or
1853 // faster since it doesn't use an intermediate texture as we do below.
1854
1855#if !GR_MAC_BUILD
1856 // At least some drivers on the Mac get confused when glTexImage2D is called
1857 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1858 // determine what OS versions and/or HW is affected.
1859 if (NULL != target->asTexture() &&
1860 GrPixelConfigIsUnpremultiplied(target->config()) ==
1861 GrPixelConfigIsUnpremultiplied(config)) {
1862
1863 this->internalWriteTexturePixels(target->asTexture(),
1864 left, top, width, height,
1865 config, buffer, rowBytes, flags);
1866 return;
1867 }
1868#endif
1869
1870 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1871 GrPixelConfigSwapRAndB(config);
1872 if (swapRAndB) {
1873 config = GrPixelConfigSwapRAndB(config);
1874 }
1875
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001876 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001877 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001878 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001879 GrAutoScratchTexture ast(this, desc);
1880 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001881 if (NULL == texture) {
1882 return;
1883 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001884 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1885 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001886
bsalomon@google.com27847de2011-02-22 20:59:41 +00001887 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001888 reset_target_state(fGpu->drawState());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889
1890 GrMatrix matrix;
1891 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1892 fGpu->setViewMatrix(matrix);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001893 fGpu->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001894 fGpu->setTexture(0, texture);
1895
bsalomon@google.com5c638652011-07-18 19:31:59 +00001896 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001897 GrSamplerState sampler;
1898 sampler.reset(GrSamplerState::kClamp_WrapMode,
1899 GrSamplerState::kNearest_Filter,
1900 matrix);
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001901 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001902 fGpu->setSamplerState(0, sampler);
1903
1904 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1905 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001906 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001907 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1908 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001909 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001910 return;
1911 }
1912 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1913 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1914}
1915////////////////////////////////////////////////////////////////////////////////
1916
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001917void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001918
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001919 GrDrawState* drawState = target->drawState();
1920
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001921 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1922 int s = i + GrPaint::kFirstTextureStage;
1923 target->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001924 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001925 target->setSamplerState(s, paint.getTextureSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001926 }
1927
1928 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1929
1930 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1931 int s = i + GrPaint::kFirstMaskStage;
1932 target->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001933 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001934 target->setSamplerState(s, paint.getMaskSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001935 }
1936
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001937 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001938
1939 if (paint.fDither) {
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001940 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001941 } else {
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001942 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001943 }
1944 if (paint.fAntiAlias) {
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001945 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946 } else {
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001947 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001948 }
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00001949 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
1950 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001951
1952 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1953 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1954 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001955}
1956
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001957GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001958 DrawCategory category) {
1959 if (category != fLastDrawCategory) {
1960 flushDrawBuffer();
1961 fLastDrawCategory = category;
1962 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001963 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001964 GrDrawTarget* target = fGpu;
1965 switch (category) {
1966 case kText_DrawCategory:
1967#if DEFER_TEXT_RENDERING
1968 target = fDrawBuffer;
1969 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1970#else
1971 target = fGpu;
1972#endif
1973 break;
1974 case kUnbuffered_DrawCategory:
1975 target = fGpu;
1976 break;
1977 case kBuffered_DrawCategory:
1978 target = fDrawBuffer;
1979 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1980 break;
1981 }
1982 return target;
1983}
1984
bsalomon@google.com289533a2011-10-27 12:34:25 +00001985GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1986 GrPathFill fill,
1987 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001988 if (NULL == fPathRendererChain) {
1989 fPathRendererChain =
1990 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1991 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001992 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1993 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001994}
1995
bsalomon@google.com27847de2011-02-22 20:59:41 +00001996////////////////////////////////////////////////////////////////////////////////
1997
bsalomon@google.com27847de2011-02-22 20:59:41 +00001998void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001999 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002000 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002001 fGpu->setRenderTarget(target);
2002}
2003
2004GrRenderTarget* GrContext::getRenderTarget() {
2005 return fGpu->getRenderTarget();
2006}
2007
2008const GrRenderTarget* GrContext::getRenderTarget() const {
2009 return fGpu->getRenderTarget();
2010}
2011
2012const GrMatrix& GrContext::getMatrix() const {
2013 return fGpu->getViewMatrix();
2014}
2015
2016void GrContext::setMatrix(const GrMatrix& m) {
2017 fGpu->setViewMatrix(m);
2018}
2019
2020void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com0fec61d2011-12-08 15:53:53 +00002021 fGpu->viewMatrix()->preConcat(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002022}
2023
2024static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2025 intptr_t mask = 1 << shift;
2026 if (pred) {
2027 bits |= mask;
2028 } else {
2029 bits &= ~mask;
2030 }
2031 return bits;
2032}
2033
2034void GrContext::resetStats() {
2035 fGpu->resetStats();
2036}
2037
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002038const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002039 return fGpu->getStats();
2040}
2041
2042void GrContext::printStats() const {
2043 fGpu->printStats();
2044}
2045
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002046GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002047 fGpu = gpu;
2048 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002049 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002050
bsalomon@google.com30085192011-08-19 15:42:31 +00002051 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002052
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002053 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2054 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002055 fFontCache = new GrFontCache(fGpu);
2056
2057 fLastDrawCategory = kUnbuffered_DrawCategory;
2058
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002059 fDrawBuffer = NULL;
2060 fDrawBufferVBAllocPool = NULL;
2061 fDrawBufferIBAllocPool = NULL;
2062
bsalomon@google.com205d4602011-04-25 12:43:45 +00002063 fAAFillRectIndexBuffer = NULL;
2064 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002065
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002066 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2067 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002068 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2069 }
2070 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002071
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002072 this->setupDrawBuffer();
2073}
2074
2075void GrContext::setupDrawBuffer() {
2076
2077 GrAssert(NULL == fDrawBuffer);
2078 GrAssert(NULL == fDrawBufferVBAllocPool);
2079 GrAssert(NULL == fDrawBufferIBAllocPool);
2080
bsalomon@google.com27847de2011-02-22 20:59:41 +00002081#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002082 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002083 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002084 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2085 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002086 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002087 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002088 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002089 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2090
bsalomon@google.com471d4712011-08-23 15:45:25 +00002091 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2092 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002093 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002094#endif
2095
2096#if BATCH_RECT_TO_RECT
2097 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2098#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002099}
2100
bsalomon@google.com27847de2011-02-22 20:59:41 +00002101GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2102 GrDrawTarget* target;
2103#if DEFER_TEXT_RENDERING
2104 target = prepareToDraw(paint, kText_DrawCategory);
2105#else
2106 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2107#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002108 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002109 return target;
2110}
2111
2112const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2113 return fGpu->getQuadIndexBuffer();
2114}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002115
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002116void GrContext::convolveInX(GrTexture* texture,
2117 const SkRect& rect,
2118 const float* kernel,
2119 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002120 ASSERT_OWNED_RESOURCE(texture);
2121
bsalomon@google.com99621082011-11-15 16:47:16 +00002122 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002123 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2124}
2125
2126void GrContext::convolveInY(GrTexture* texture,
2127 const SkRect& rect,
2128 const float* kernel,
2129 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002130 ASSERT_OWNED_RESOURCE(texture);
2131
bsalomon@google.com99621082011-11-15 16:47:16 +00002132 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002133 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2134}
2135
2136void GrContext::convolve(GrTexture* texture,
2137 const SkRect& rect,
2138 float imageIncrement[2],
2139 const float* kernel,
2140 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002141 ASSERT_OWNED_RESOURCE(texture);
2142
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002143 GrDrawTarget::AutoStateRestore asr(fGpu);
2144 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +00002145 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002146 GrSamplerState::kConvolution_Filter);
2147 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002148 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002149 sampler.setMatrix(sampleM);
2150 fGpu->setSamplerState(0, sampler);
2151 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002152 fGpu->setTexture(0, texture);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002153 fGpu->setColor(0xFFFFFFFF);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002154 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002155 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2156}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002157
2158///////////////////////////////////////////////////////////////////////////////