blob: f4559843136dfed953de6c1a4659f1f0de567101 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
tomhudson@google.com278cbb42011-06-30 19:37:01 +000010#include "GrBufferAllocPool.h"
11#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000012#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000013#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000014#include "GrIndexBuffer.h"
15#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000016#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000017#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000018#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000019#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000020#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000021#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000022#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023
bsalomon@google.com91958362011-06-13 17:58:13 +000024// Using MSAA seems to be slower for some yet unknown reason.
25#define PREFER_MSAA_OFFSCREEN_AA 0
26#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000027
bsalomon@google.com27847de2011-02-22 20:59:41 +000028#define DEFER_TEXT_RENDERING 1
29
30#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
31
bsalomon@google.comd46e2422011-09-23 17:40:07 +000032// When we're using coverage AA but the blend is incompatible (given gpu
33// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000034#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000035
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000036static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
37static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000038
39static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
40static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
41
42// We are currently only batching Text and drawRectToRect, both
43// of which use the quad index buffer.
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
46
bsalomon@google.combc4b6542011-11-19 13:56:11 +000047#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
48
bsalomon@google.com05ef5102011-05-02 21:14:59 +000049GrContext* GrContext::Create(GrEngine engine,
50 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000051 GrContext* ctx = NULL;
52 GrGpu* fGpu = GrGpu::Create(engine, context3D);
53 if (NULL != fGpu) {
54 ctx = new GrContext(fGpu);
55 fGpu->unref();
56 }
57 return ctx;
58}
59
bsalomon@google.com27847de2011-02-22 20:59:41 +000060GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000061 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000062 delete fTextureCache;
63 delete fFontCache;
64 delete fDrawBuffer;
65 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000066 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000067
bsalomon@google.com205d4602011-04-25 12:43:45 +000068 GrSafeUnref(fAAFillRectIndexBuffer);
69 GrSafeUnref(fAAStrokeRectIndexBuffer);
70 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000071 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000072}
73
bsalomon@google.com8fe72472011-03-30 21:26:44 +000074void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000075 contextDestroyed();
76 this->setupDrawBuffer();
77}
78
79void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000080 // abandon first to so destructors
81 // don't try to free the resources in the API.
82 fGpu->abandonResources();
83
bsalomon@google.com30085192011-08-19 15:42:31 +000084 // a path renderer may be holding onto resources that
85 // are now unusable
86 GrSafeSetNull(fPathRendererChain);
87
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBuffer;
89 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferVBAllocPool;
92 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000093
bsalomon@google.com8fe72472011-03-30 21:26:44 +000094 delete fDrawBufferIBAllocPool;
95 fDrawBufferIBAllocPool = NULL;
96
bsalomon@google.com205d4602011-04-25 12:43:45 +000097 GrSafeSetNull(fAAFillRectIndexBuffer);
98 GrSafeSetNull(fAAStrokeRectIndexBuffer);
99
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100 fTextureCache->removeAll();
101 fFontCache->freeAll();
102 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000103}
104
105void GrContext::resetContext() {
106 fGpu->markContextDirty();
107}
108
109void GrContext::freeGpuResources() {
110 this->flush();
111 fTextureCache->removeAll();
112 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000113 // a path renderer may be holding onto resources
114 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000115}
116
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000117////////////////////////////////////////////////////////////////////////////////
118
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000119int GrContext::PaintStageVertexLayoutBits(
120 const GrPaint& paint,
121 const bool hasTexCoords[GrPaint::kTotalStages]) {
122 int stageMask = paint.getActiveStageMask();
123 int layout = 0;
124 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
125 if ((1 << i) & stageMask) {
126 if (NULL != hasTexCoords && hasTexCoords[i]) {
127 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
128 } else {
129 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
130 }
131 }
132 }
133 return layout;
134}
135
136
137////////////////////////////////////////////////////////////////////////////////
138
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000139enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000140 // flags for textures
141 kNPOTBit = 0x1,
142 kFilterBit = 0x2,
143 kScratchBit = 0x4,
144
145 // resource type
146 kTextureBit = 0x8,
147 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000148};
149
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000150GrTexture* GrContext::TextureCacheEntry::texture() const {
151 if (NULL == fEntry) {
152 return NULL;
153 } else {
154 return (GrTexture*) fEntry->resource();
155 }
156}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000157
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000158namespace {
159// returns true if this is a "special" texture because of gpu NPOT limitations
160bool gen_texture_key_values(const GrGpu* gpu,
161 const GrSamplerState& sampler,
162 GrContext::TextureKey clientKey,
163 int width,
164 int height,
165 bool scratch,
166 uint32_t v[4]) {
167 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
168 // we assume we only need 16 bits of width and height
169 // assert that texture creation will fail anyway if this assumption
170 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000171 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000172 v[0] = clientKey & 0xffffffffUL;
173 v[1] = (clientKey >> 32) & 0xffffffffUL;
174 v[2] = width | (height << 16);
175
176 v[3] = 0;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000177 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000178 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
179
180 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
181 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
182
183 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000184 v[3] |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000185 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000186 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000187 }
188 }
189 }
190
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191 if (scratch) {
192 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000193 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000194
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000195 v[3] |= kTextureBit;
196
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000197 return v[3] & kNPOTBit;
198}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000199
200// we should never have more than one stencil buffer with same combo of
201// (width,height,samplecount)
202void gen_stencil_key_values(int width, int height,
203 int sampleCnt, uint32_t v[4]) {
204 v[0] = width;
205 v[1] = height;
206 v[2] = sampleCnt;
207 v[3] = kStencilBufferBit;
208}
209
210void gen_stencil_key_values(const GrStencilBuffer* sb,
211 uint32_t v[4]) {
212 gen_stencil_key_values(sb->width(), sb->height(),
213 sb->numSamples(), v);
214}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000215
216// This should be subsumed by a future version of GrDrawState
217// It does not reset stage textures/samplers or per-vertex-edge-aa state since
218// they aren't used unless the vertex layout references them.
219// It also doesn't set the render target.
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000220void reset_target_state(GrDrawTarget* target){
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000221 GrDrawState* drawState = target->drawState();
222
223 drawState->setViewMatrix(GrMatrix::I());
224 drawState->setColorFilter(0, SkXfermode::kDst_Mode);
225 drawState->disableState(GrDrawState::kDither_StateBit |
226 GrDrawState::kHWAntialias_StateBit |
227 GrDrawState::kClip_StateBit |
228 GrDrawState::kNoColorWrites_StateBit |
229 GrDrawState::kEdgeAAConcave_StateBit);
230 drawState->setEdgeAAData(NULL, 0);
231 drawState->disableStencil();
232 drawState->setAlpha(0xFF);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000233 target->setBlendFunc(kOne_BlendCoeff,
234 kZero_BlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000235 drawState->setFirstCoverageStage(GrDrawState::kNumStages);
236 drawState->setDrawFace(GrDrawState::kBoth_DrawFace);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000237}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000238}
239
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000240GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
241 int width,
242 int height,
243 const GrSamplerState& sampler) {
244 uint32_t v[4];
245 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
246 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000247 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
248 GrResourceCache::kNested_LockType));
249}
250
bsalomon@google.comfb309512011-11-30 14:13:48 +0000251bool GrContext::isTextureInCache(TextureKey key,
252 int width,
253 int height,
254 const GrSamplerState& sampler) const {
255 uint32_t v[4];
256 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
257 GrResourceKey resourceKey(v);
258 return fTextureCache->hasKey(resourceKey);
259}
260
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000261GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000262 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000263 uint32_t v[4];
264 gen_stencil_key_values(sb, v);
265 GrResourceKey resourceKey(v);
266 return fTextureCache->createAndLock(resourceKey, sb);
267}
268
269GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
270 int sampleCnt) {
271 uint32_t v[4];
272 gen_stencil_key_values(width, height, sampleCnt, v);
273 GrResourceKey resourceKey(v);
274 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
275 GrResourceCache::kSingle_LockType);
276 if (NULL != entry) {
277 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
278 return sb;
279 } else {
280 return NULL;
281 }
282}
283
284void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000285 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000286 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000287}
288
289static void stretchImage(void* dst,
290 int dstW,
291 int dstH,
292 void* src,
293 int srcW,
294 int srcH,
295 int bpp) {
296 GrFixed dx = (srcW << 16) / dstW;
297 GrFixed dy = (srcH << 16) / dstH;
298
299 GrFixed y = dy >> 1;
300
301 int dstXLimit = dstW*bpp;
302 for (int j = 0; j < dstH; ++j) {
303 GrFixed x = dx >> 1;
304 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
305 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
306 for (int i = 0; i < dstXLimit; i += bpp) {
307 memcpy((uint8_t*) dstRow + i,
308 (uint8_t*) srcRow + (x>>16)*bpp,
309 bpp);
310 x += dx;
311 }
312 y += dy;
313 }
314}
315
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000316GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000317 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000318 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000319 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000320 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000321
322#if GR_DUMP_TEXTURE_UPLOAD
323 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
324#endif
325
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000326 TextureCacheEntry entry;
327 uint32_t v[4];
328 bool special = gen_texture_key_values(fGpu, sampler, key,
329 desc.fWidth, desc.fHeight, false, v);
330 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000331
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000332 if (special) {
333 TextureCacheEntry clampEntry =
334 findAndLockTexture(key, desc.fWidth, desc.fHeight,
bsalomon@google.com97912912011-12-06 16:30:36 +0000335 GrSamplerState::ClampNearest());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000336
337 if (NULL == clampEntry.texture()) {
338 clampEntry = createAndLockTexture(key,
bsalomon@google.com97912912011-12-06 16:30:36 +0000339 GrSamplerState::ClampNearest(),
bsalomon@google.com27847de2011-02-22 20:59:41 +0000340 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000341 GrAssert(NULL != clampEntry.texture());
342 if (NULL == clampEntry.texture()) {
343 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000344 }
345 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000346 GrTextureDesc rtDesc = desc;
347 rtDesc.fFlags = rtDesc.fFlags |
348 kRenderTarget_GrTextureFlagBit |
349 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000350 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
351 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000352
353 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
354
355 if (NULL != texture) {
356 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000357 reset_target_state(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000358 GrDrawState* drawState = fGpu->drawState();
359 drawState->setRenderTarget(texture->asRenderTarget());
360 drawState->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000361
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000362 GrSamplerState::Filter filter;
363 // if filtering is not desired then we want to ensure all
364 // texels in the resampled image are copies of texels from
365 // the original.
366 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
367 filter = GrSamplerState::kNearest_Filter;
368 } else {
369 filter = GrSamplerState::kBilinear_Filter;
370 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000371 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000372 filter);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000373 drawState->setSampler(0, stretchSampler);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000374
375 static const GrVertexLayout layout =
376 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
377 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
378
379 if (arg.succeeded()) {
380 GrPoint* verts = (GrPoint*) arg.vertices();
381 verts[0].setIRectFan(0, 0,
382 texture->width(),
383 texture->height(),
384 2*sizeof(GrPoint));
385 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
386 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
387 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000388 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000389 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000390 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000391 } else {
392 // TODO: Our CPU stretch doesn't filter. But we create separate
393 // stretched textures when the sampler state is either filtered or
394 // not. Either implement filtered stretch blit on CPU or just create
395 // one when FBO case fails.
396
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000397 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000398 // no longer need to clamp at min RT size.
399 rtDesc.fWidth = GrNextPow2(desc.fWidth);
400 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000401 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000402 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000403 rtDesc.fWidth *
404 rtDesc.fHeight);
405 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
406 srcData, desc.fWidth, desc.fHeight, bpp);
407
408 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
409
410 GrTexture* texture = fGpu->createTexture(rtDesc,
411 stretchedPixels.get(),
412 stretchedRowBytes);
413 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000417
418 } else {
419 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
420 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000421 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000422 }
423 }
424 return entry;
425}
426
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000427namespace {
428inline void gen_scratch_tex_key_values(const GrGpu* gpu,
429 const GrTextureDesc& desc,
430 uint32_t v[4]) {
431 // Instead of a client-provided key of the texture contents
432 // we create a key of from the descriptor.
433 GrContext::TextureKey descKey = desc.fAALevel |
434 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000435 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000436 // this code path isn't friendly to tiling with NPOT restricitons
437 // We just pass ClampNoFilter()
bsalomon@google.com97912912011-12-06 16:30:36 +0000438 gen_texture_key_values(gpu, GrSamplerState::ClampNearest(), descKey,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000439 desc.fWidth, desc.fHeight, true, v);
440}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000441}
442
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000443GrContext::TextureCacheEntry GrContext::lockScratchTexture(
444 const GrTextureDesc& inDesc,
445 ScratchTexMatch match) {
446
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000447 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000448 if (kExact_ScratchTexMatch != match) {
449 // bin by pow2 with a reasonable min
450 static const int MIN_SIZE = 256;
451 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
452 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
453 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000454
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000455 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000456 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
457
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000458 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000459 int origWidth = desc.fWidth;
460 int origHeight = desc.fHeight;
461 bool doubledW = false;
462 bool doubledH = false;
463
464 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000465 uint32_t v[4];
466 gen_scratch_tex_key_values(fGpu, desc, v);
467 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000468 entry = fTextureCache->findAndLock(key,
469 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000470 // if we miss, relax the fit of the flags...
471 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000472 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000473 break;
474 }
475 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
476 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
477 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
478 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
479 } else if (!doubledW) {
480 desc.fFlags = inDesc.fFlags;
481 desc.fWidth *= 2;
482 doubledW = true;
483 } else if (!doubledH) {
484 desc.fFlags = inDesc.fFlags;
485 desc.fWidth = origWidth;
486 desc.fHeight *= 2;
487 doubledH = true;
488 } else {
489 break;
490 }
491
492 } while (true);
493
494 if (NULL == entry) {
495 desc.fFlags = inDesc.fFlags;
496 desc.fWidth = origWidth;
497 desc.fHeight = origHeight;
498 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
499 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000500 uint32_t v[4];
501 gen_scratch_tex_key_values(fGpu, desc, v);
502 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000503 entry = fTextureCache->createAndLock(key, texture);
504 }
505 }
506
507 // If the caller gives us the same desc/sampler twice we don't want
508 // to return the same texture the second time (unless it was previously
509 // released). So we detach the entry from the cache and reattach at release.
510 if (NULL != entry) {
511 fTextureCache->detach(entry);
512 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000514}
515
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000516void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000517 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000518 // If this is a scratch texture we detached it from the cache
519 // while it was locked (to avoid two callers simultaneously getting
520 // the same texture).
521 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
522 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000523 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000524 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000525 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000526}
527
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000528GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000529 void* srcData,
530 size_t rowBytes) {
531 return fGpu->createTexture(desc, srcData, rowBytes);
532}
533
534void GrContext::getTextureCacheLimits(int* maxTextures,
535 size_t* maxTextureBytes) const {
536 fTextureCache->getLimits(maxTextures, maxTextureBytes);
537}
538
539void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
540 fTextureCache->setLimits(maxTextures, maxTextureBytes);
541}
542
bsalomon@google.com91958362011-06-13 17:58:13 +0000543int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000544 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000545}
546
547int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000548 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000549}
550
551///////////////////////////////////////////////////////////////////////////////
552
bsalomon@google.come269f212011-11-07 13:29:52 +0000553GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
554 return fGpu->createPlatformTexture(desc);
555}
556
557GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
558 return fGpu->createPlatformRenderTarget(desc);
559}
560
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000561GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
562 // validate flags here so that GrGpu subclasses don't have to check
563 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
564 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000565 return NULL;
566 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000567 if (desc.fSampleCnt &&
568 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000569 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000570 }
571 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
572 desc.fSampleCnt &&
573 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
574 return NULL;
575 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000576 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577}
578
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000579///////////////////////////////////////////////////////////////////////////////
580
bsalomon@google.com27847de2011-02-22 20:59:41 +0000581bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000582 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000583 const GrDrawTarget::Caps& caps = fGpu->getCaps();
584 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000585 return false;
586 }
587
bsalomon@google.com27847de2011-02-22 20:59:41 +0000588 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
589
590 if (!isPow2) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000591 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
592 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000593 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000594 return false;
595 }
596 }
597 return true;
598}
599
600////////////////////////////////////////////////////////////////////////////////
601
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000602const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
603
bsalomon@google.com27847de2011-02-22 20:59:41 +0000604void GrContext::setClip(const GrClip& clip) {
605 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000606 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000607}
608
609void GrContext::setClip(const GrIRect& rect) {
610 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000611 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000612 fGpu->setClip(clip);
613}
614
615////////////////////////////////////////////////////////////////////////////////
616
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000617void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000618 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000619 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000620}
621
622void GrContext::drawPaint(const GrPaint& paint) {
623 // set rect to be big enough to fill the space, but not super-huge, so we
624 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000625 GrRect r;
626 r.setLTRB(0, 0,
627 GrIntToScalar(getRenderTarget()->width()),
628 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000629 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000630 SkTLazy<GrPaint> tmpPaint;
631 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000632 GrDrawState* drawState = fGpu->drawState();
633 GrAutoMatrix am;
634
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000635 // We attempt to map r by the inverse matrix and draw that. mapRect will
636 // map the four corners and bound them with a new rect. This will not
637 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000638 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000639 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000640 GrPrintf("Could not invert matrix");
641 return;
642 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000643 inverse.mapRect(&r);
644 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000645 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000646 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000647 GrPrintf("Could not invert matrix");
648 return;
649 }
650 tmpPaint.set(paint);
651 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
652 p = tmpPaint.get();
653 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000654 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000655 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000656 // by definition this fills the entire clip, no need for AA
657 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000658 if (!tmpPaint.isValid()) {
659 tmpPaint.set(paint);
660 p = tmpPaint.get();
661 }
662 GrAssert(p == tmpPaint.get());
663 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000664 }
665 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000666}
667
bsalomon@google.com205d4602011-04-25 12:43:45 +0000668////////////////////////////////////////////////////////////////////////////////
669
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000670namespace {
671inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
672 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
673}
674}
675
bsalomon@google.com91958362011-06-13 17:58:13 +0000676struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000677 enum Downsample {
678 k4x4TwoPass_Downsample,
679 k4x4SinglePass_Downsample,
680 kFSAA_Downsample
681 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000682 int fTileSizeX;
683 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000684 int fTileCountX;
685 int fTileCountY;
686 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000687 GrAutoScratchTexture fOffscreen0;
688 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000689 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000690 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000691};
692
bsalomon@google.com471d4712011-08-23 15:45:25 +0000693bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000694 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000695#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000696 return false;
697#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000698 // Line primitves are always rasterized as 1 pixel wide.
699 // Super-sampling would make them too thin but MSAA would be OK.
700 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000701 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000702 return false;
703 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000704 if (target->getDrawState().getRenderTarget()->isMultisampled()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000705 return false;
706 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000707 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000708#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000709 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000710#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000711 return false;
712 }
713 return true;
714#endif
715}
716
bsalomon@google.com91958362011-06-13 17:58:13 +0000717bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000718 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000719 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000720 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000721 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000722
723 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000724
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000725 GrAssert(NULL == record->fOffscreen0.texture());
726 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000727 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000728
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000729 int boundW = boundRect.width();
730 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000731
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000732 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000733
734 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
735 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
736
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000737 if (requireStencil) {
738 desc.fFlags = kRenderTarget_GrTextureFlagBit;
739 } else {
740 desc.fFlags = kRenderTarget_GrTextureFlagBit |
741 kNoStencil_GrTextureFlagBit;
742 }
743
bsalomon@google.comc4364992011-11-07 15:54:49 +0000744 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000745
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000746 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000747 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000748 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000749 desc.fAALevel = kMed_GrAALevel;
750 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000751 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000752 OffscreenRecord::k4x4SinglePass_Downsample :
753 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000754 record->fScale = OFFSCREEN_SSAA_SCALE;
755 // both downsample paths assume this
756 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000757 desc.fAALevel = kNone_GrAALevel;
758 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000759
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000760 desc.fWidth *= record->fScale;
761 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000762 record->fOffscreen0.set(this, desc);
763 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000764 return false;
765 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000766 // the approximate lookup might have given us some slop space, might as well
767 // use it when computing the tiles size.
768 // these are scale values, will adjust after considering
769 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000770 record->fTileSizeX = record->fOffscreen0.texture()->width();
771 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000772
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000773 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000774 desc.fWidth /= 2;
775 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000776 record->fOffscreen1.set(this, desc);
777 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000778 return false;
779 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000780 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000781 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000782 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000783 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000784 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000785 record->fTileSizeX /= record->fScale;
786 record->fTileSizeY /= record->fScale;
787
788 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
789 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
790
tomhudson@google.com237a4612011-07-19 15:44:00 +0000791 record->fClip = target->getClip();
792
bsalomon@google.com91958362011-06-13 17:58:13 +0000793 target->saveCurrentDrawState(&record->fSavedState);
794 return true;
795}
796
797void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
798 const GrIRect& boundRect,
799 int tileX, int tileY,
800 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000801
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000802 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000803 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000804
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000805 GrPaint tempPaint;
806 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000807 this->setPaint(tempPaint, target);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000808 GrDrawState* drawState = target->drawState();
809 drawState->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000810#if PREFER_MSAA_OFFSCREEN_AA
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000811 target->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000812#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000813
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000814 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000815 int left = boundRect.fLeft + tileX * record->fTileSizeX;
816 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000817 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000818 drawState->viewMatrix()->postConcat(transM);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +0000819 GrMatrix scaleM;
820 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000821 drawState->viewMatrix()->postConcat(scaleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000822
bsalomon@google.com91958362011-06-13 17:58:13 +0000823 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000824 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000825 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000826 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000827 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
828 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000829 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000830#if 0
831 // visualize tile boundaries by setting edges of offscreen to white
832 // and interior to tranparent. black.
833 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000834
bsalomon@google.com91958362011-06-13 17:58:13 +0000835 static const int gOffset = 2;
836 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
837 record->fScale * w - gOffset,
838 record->fScale * h - gOffset);
839 target->clear(&clear2, 0x0);
840#else
841 target->clear(&clear, 0x0);
842#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000843}
844
bsalomon@google.com91958362011-06-13 17:58:13 +0000845void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000846 const GrPaint& paint,
847 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000848 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000849 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000850 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000851 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000852 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000853 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000854 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
855 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000856 tileRect.fRight = (tileX == record->fTileCountX-1) ?
857 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000858 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000859 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
860 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000861 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000862
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000863 GrSamplerState::Filter filter;
864 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
865 filter = GrSamplerState::k4x4Downsample_Filter;
866 } else {
867 filter = GrSamplerState::kBilinear_Filter;
868 }
869
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000870 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +0000871 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000872
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000873 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000874 int scale;
875
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000876 enum {
877 kOffscreenStage = GrPaint::kTotalStages,
878 };
879
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000880 GrDrawState* drawState = target->drawState();
881
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000882 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000883 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000884 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000885 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000886
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000887 // Do 2x2 downsample from first to second
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000888 drawState->setTexture(kOffscreenStage, src);
889 drawState->setRenderTarget(dst);
890 drawState->setViewMatrix(GrMatrix::I());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000891 sampleM.setScale(scale * GR_Scalar1 / src->width(),
892 scale * GR_Scalar1 / src->height());
893 sampler.setMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000894 drawState->setSampler(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000895 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
896 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000897 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
898
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000899 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000900 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000901 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000902 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000903 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000904 } else {
905 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
906 record->fDownsample);
907 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000908 }
909
bsalomon@google.com91958362011-06-13 17:58:13 +0000910 // setup for draw back to main RT, we use the original
911 // draw state setup by the caller plus an additional coverage
912 // stage to handle the AA resolve. Also, we use an identity
913 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000914 int stageMask = paint.getActiveStageMask();
915
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000916 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000917 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000918
919 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000920 GrMatrix invVM;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000921 if (drawState->getViewInverse(&invVM)) {
922 drawState->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000923 }
924 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000925 // This is important when tiling, otherwise second tile's
926 // pass 1 view matrix will be incorrect.
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000927 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I());
bsalomon@google.com91958362011-06-13 17:58:13 +0000928
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000929 drawState->setTexture(kOffscreenStage, src);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000930 sampleM.setScale(scale * GR_Scalar1 / src->width(),
931 scale * GR_Scalar1 / src->height());
932 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000933 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
934 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000935 sampler.preConcatMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000936 drawState->setSampler(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000937
reed@google.com20efde72011-05-09 17:00:02 +0000938 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000939 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000940 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000941 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000942}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000943
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000944void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
945 GrPathRenderer* pr,
946 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000947 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000948}
949
950////////////////////////////////////////////////////////////////////////////////
951
bsalomon@google.com27847de2011-02-22 20:59:41 +0000952/* create a triangle strip that strokes the specified triangle. There are 8
953 unique vertices, but we repreat the last 2 to close up. Alternatively we
954 could use an indices array, and then only send 8 verts, but not sure that
955 would be faster.
956 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000957static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000958 GrScalar width) {
959 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000960 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000961
962 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
963 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
964 verts[2].set(rect.fRight - rad, rect.fTop + rad);
965 verts[3].set(rect.fRight + rad, rect.fTop - rad);
966 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
967 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
968 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
969 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
970 verts[8] = verts[0];
971 verts[9] = verts[1];
972}
973
bsalomon@google.com205d4602011-04-25 12:43:45 +0000974static void setInsetFan(GrPoint* pts, size_t stride,
975 const GrRect& r, GrScalar dx, GrScalar dy) {
976 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
977}
978
979static const uint16_t gFillAARectIdx[] = {
980 0, 1, 5, 5, 4, 0,
981 1, 2, 6, 6, 5, 1,
982 2, 3, 7, 7, 6, 2,
983 3, 0, 4, 4, 7, 3,
984 4, 5, 6, 6, 7, 4,
985};
986
987int GrContext::aaFillRectIndexCount() const {
988 return GR_ARRAY_COUNT(gFillAARectIdx);
989}
990
991GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
992 if (NULL == fAAFillRectIndexBuffer) {
993 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
994 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000995 if (NULL != fAAFillRectIndexBuffer) {
996 #if GR_DEBUG
997 bool updated =
998 #endif
999 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
1000 sizeof(gFillAARectIdx));
1001 GR_DEBUGASSERT(updated);
1002 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001003 }
1004 return fAAFillRectIndexBuffer;
1005}
1006
1007static const uint16_t gStrokeAARectIdx[] = {
1008 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
1009 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
1010 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
1011 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
1012
1013 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1014 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1015 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1016 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1017
1018 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1019 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1020 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1021 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1022};
1023
1024int GrContext::aaStrokeRectIndexCount() const {
1025 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1026}
1027
1028GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1029 if (NULL == fAAStrokeRectIndexBuffer) {
1030 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1031 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001032 if (NULL != fAAStrokeRectIndexBuffer) {
1033 #if GR_DEBUG
1034 bool updated =
1035 #endif
1036 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1037 sizeof(gStrokeAARectIdx));
1038 GR_DEBUGASSERT(updated);
1039 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001040 }
1041 return fAAStrokeRectIndexBuffer;
1042}
1043
bsalomon@google.coma3108262011-10-10 14:08:47 +00001044static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1045 bool useCoverage) {
1046 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001047 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001048 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001049 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1050 }
1051 }
1052 if (useCoverage) {
1053 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1054 } else {
1055 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1056 }
1057 return layout;
1058}
1059
bsalomon@google.com205d4602011-04-25 12:43:45 +00001060void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001061 const GrRect& devRect,
1062 bool useVertexCoverage) {
1063 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001064
1065 size_t vsize = GrDrawTarget::VertexSize(layout);
1066
1067 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001068 if (!geo.succeeded()) {
1069 GrPrintf("Failed to get space for vertices!\n");
1070 return;
1071 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001072 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1073 if (NULL == indexBuffer) {
1074 GrPrintf("Failed to create index buffer!\n");
1075 return;
1076 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001077
1078 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1079
1080 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1081 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1082
1083 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1084 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1085
1086 verts += sizeof(GrPoint);
1087 for (int i = 0; i < 4; ++i) {
1088 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1089 }
1090
bsalomon@google.coma3108262011-10-10 14:08:47 +00001091 GrColor innerColor;
1092 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001093 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001094 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001095 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001096 }
1097
bsalomon@google.com205d4602011-04-25 12:43:45 +00001098 verts += 4 * vsize;
1099 for (int i = 0; i < 4; ++i) {
1100 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1101 }
1102
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001103 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001104
1105 target->drawIndexed(kTriangles_PrimitiveType, 0,
1106 0, 8, this->aaFillRectIndexCount());
1107}
1108
bsalomon@google.coma3108262011-10-10 14:08:47 +00001109void GrContext::strokeAARect(GrDrawTarget* target,
1110 const GrRect& devRect,
1111 const GrVec& devStrokeSize,
1112 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001113 const GrScalar& dx = devStrokeSize.fX;
1114 const GrScalar& dy = devStrokeSize.fY;
1115 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1116 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1117
bsalomon@google.com205d4602011-04-25 12:43:45 +00001118 GrScalar spare;
1119 {
1120 GrScalar w = devRect.width() - dx;
1121 GrScalar h = devRect.height() - dy;
1122 spare = GrMin(w, h);
1123 }
1124
1125 if (spare <= 0) {
1126 GrRect r(devRect);
1127 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001128 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001129 return;
1130 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001131 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001132 size_t vsize = GrDrawTarget::VertexSize(layout);
1133
1134 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001135 if (!geo.succeeded()) {
1136 GrPrintf("Failed to get space for vertices!\n");
1137 return;
1138 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001139 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1140 if (NULL == indexBuffer) {
1141 GrPrintf("Failed to create index buffer!\n");
1142 return;
1143 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001144
1145 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1146
1147 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1148 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1149 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1150 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1151
1152 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1153 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1154 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1155 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1156
1157 verts += sizeof(GrPoint);
1158 for (int i = 0; i < 4; ++i) {
1159 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1160 }
1161
bsalomon@google.coma3108262011-10-10 14:08:47 +00001162 GrColor innerColor;
1163 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001164 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001165 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001166 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +00001167 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001168 verts += 4 * vsize;
1169 for (int i = 0; i < 8; ++i) {
1170 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1171 }
1172
1173 verts += 8 * vsize;
1174 for (int i = 0; i < 8; ++i) {
1175 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1176 }
1177
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001178 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001179 target->drawIndexed(kTriangles_PrimitiveType,
1180 0, 0, 16, aaStrokeRectIndexCount());
1181}
1182
reed@google.com20efde72011-05-09 17:00:02 +00001183/**
1184 * Returns true if the rects edges are integer-aligned.
1185 */
1186static bool isIRect(const GrRect& r) {
1187 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1188 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1189}
1190
bsalomon@google.com205d4602011-04-25 12:43:45 +00001191static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001192 const GrRect& rect,
1193 GrScalar width,
1194 const GrMatrix* matrix,
1195 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001196 GrRect* devRect,
1197 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001198 // we use a simple alpha ramp to do aa on axis-aligned rects
1199 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001200 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001201
bsalomon@google.coma3108262011-10-10 14:08:47 +00001202 // we are keeping around the "tweak the alpha" trick because
1203 // it is our only hope for the fixed-pipe implementation.
1204 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001205 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001206 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001207 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001208 if (target->getCaps().fSupportPerVertexCoverage) {
1209 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001210#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001211 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001212#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001213 return false;
1214 } else {
1215 *useVertexCoverage = true;
1216 }
1217 } else {
1218 GrPrintf("Rect AA dropped because no support for coverage.\n");
1219 return false;
1220 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001221 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001222 const GrDrawState& drawState = target->getDrawState();
1223 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001224 return false;
1225 }
1226
bsalomon@google.com471d4712011-08-23 15:45:25 +00001227 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001228 return false;
1229 }
1230
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001231 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001232 return false;
1233 }
1234
1235 if (NULL != matrix &&
1236 !matrix->preservesAxisAlignment()) {
1237 return false;
1238 }
1239
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001240 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +00001241 if (NULL != matrix) {
1242 combinedMatrix->preConcat(*matrix);
1243 GrAssert(combinedMatrix->preservesAxisAlignment());
1244 }
1245
1246 combinedMatrix->mapRect(devRect, rect);
1247 devRect->sort();
1248
1249 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001250 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001251 } else {
1252 return true;
1253 }
1254}
1255
bsalomon@google.com27847de2011-02-22 20:59:41 +00001256void GrContext::drawRect(const GrPaint& paint,
1257 const GrRect& rect,
1258 GrScalar width,
1259 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001260 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001261
1262 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001263 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001264
bsalomon@google.com205d4602011-04-25 12:43:45 +00001265 GrRect devRect = rect;
1266 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001267 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001268 bool needAA = paint.fAntiAlias &&
1269 !this->getRenderTarget()->isMultisampled();
1270 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1271 &combinedMatrix, &devRect,
1272 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001273
1274 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001275 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001276 if (width >= 0) {
1277 GrVec strokeSize;;
1278 if (width > 0) {
1279 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001280 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001281 strokeSize.setAbs(strokeSize);
1282 } else {
1283 strokeSize.set(GR_Scalar1, GR_Scalar1);
1284 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001285 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001286 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001287 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001288 }
1289 return;
1290 }
1291
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292 if (width >= 0) {
1293 // TODO: consider making static vertex buffers for these cases.
1294 // Hairline could be done by just adding closing vertex to
1295 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001296 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1297
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298 static const int worstCaseVertCount = 10;
1299 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1300
1301 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001302 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001303 return;
1304 }
1305
1306 GrPrimitiveType primType;
1307 int vertCount;
1308 GrPoint* vertex = geo.positions();
1309
1310 if (width > 0) {
1311 vertCount = 10;
1312 primType = kTriangleStrip_PrimitiveType;
1313 setStrokeRectStrip(vertex, rect, width);
1314 } else {
1315 // hairline
1316 vertCount = 5;
1317 primType = kLineStrip_PrimitiveType;
1318 vertex[0].set(rect.fLeft, rect.fTop);
1319 vertex[1].set(rect.fRight, rect.fTop);
1320 vertex[2].set(rect.fRight, rect.fBottom);
1321 vertex[3].set(rect.fLeft, rect.fBottom);
1322 vertex[4].set(rect.fLeft, rect.fTop);
1323 }
1324
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001325 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001327 GrDrawState* drawState = target->drawState();
1328 avmr.set(drawState);
1329 drawState->preConcatViewMatrix(*matrix);
1330 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001331 }
1332
1333 target->drawNonIndexed(primType, 0, vertCount);
1334 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001335#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001336 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001337 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1338 if (NULL == sqVB) {
1339 GrPrintf("Failed to create static rect vb.\n");
1340 return;
1341 }
1342 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001343 GrDrawState* drawState = target->drawState();
1344 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001345 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001346 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001347 0, rect.height(), rect.fTop,
1348 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001349
1350 if (NULL != matrix) {
1351 m.postConcat(*matrix);
1352 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001353 drawState->preConcatViewMatrix(m);
1354 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001355
bsalomon@google.com27847de2011-02-22 20:59:41 +00001356 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001357#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001358 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001359#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001360 }
1361}
1362
1363void GrContext::drawRectToRect(const GrPaint& paint,
1364 const GrRect& dstRect,
1365 const GrRect& srcRect,
1366 const GrMatrix* dstMatrix,
1367 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001368 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001369
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001370 // srcRect refers to paint's first texture
1371 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001372 drawRect(paint, dstRect, -1, dstMatrix);
1373 return;
1374 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001375
bsalomon@google.com27847de2011-02-22 20:59:41 +00001376 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1377
1378#if GR_STATIC_RECT_VB
1379 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001380 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001381 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001382 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001383
1384 GrMatrix m;
1385
1386 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1387 0, dstRect.height(), dstRect.fTop,
1388 0, 0, GrMatrix::I()[8]);
1389 if (NULL != dstMatrix) {
1390 m.postConcat(*dstMatrix);
1391 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001392 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001393
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001394 // srcRect refers to first stage
1395 int otherStageMask = paint.getActiveStageMask() &
1396 (~(1 << GrPaint::kFirstTextureStage));
1397 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001398 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001399 }
1400
bsalomon@google.com27847de2011-02-22 20:59:41 +00001401 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1402 0, srcRect.height(), srcRect.fTop,
1403 0, 0, GrMatrix::I()[8]);
1404 if (NULL != srcMatrix) {
1405 m.postConcat(*srcMatrix);
1406 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001407 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001408
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001409 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1410 if (NULL == sqVB) {
1411 GrPrintf("Failed to create static rect vb.\n");
1412 return;
1413 }
1414 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1416#else
1417
1418 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001419#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001421#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001422 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1423#endif
1424
tomhudson@google.com93813632011-10-27 20:21:16 +00001425 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1426 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001427 srcRects[0] = &srcRect;
1428 srcMatrices[0] = srcMatrix;
1429
1430 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1431#endif
1432}
1433
1434void GrContext::drawVertices(const GrPaint& paint,
1435 GrPrimitiveType primitiveType,
1436 int vertexCount,
1437 const GrPoint positions[],
1438 const GrPoint texCoords[],
1439 const GrColor colors[],
1440 const uint16_t indices[],
1441 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001442 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001443
1444 GrDrawTarget::AutoReleaseGeometry geo;
1445
1446 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1447
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001448 bool hasTexCoords[GrPaint::kTotalStages] = {
1449 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1450 0 // remaining stages use positions
1451 };
1452
1453 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001454
1455 if (NULL != colors) {
1456 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001457 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001458 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001459
1460 if (sizeof(GrPoint) != vertexSize) {
1461 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001462 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463 return;
1464 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001465 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001467 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1468 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001469 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001470 NULL,
1471 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472 void* curVertex = geo.vertices();
1473
1474 for (int i = 0; i < vertexCount; ++i) {
1475 *((GrPoint*)curVertex) = positions[i];
1476
1477 if (texOffsets[0] > 0) {
1478 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1479 }
1480 if (colorOffset > 0) {
1481 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1482 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001483 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001484 }
1485 } else {
1486 target->setVertexSourceToArray(layout, positions, vertexCount);
1487 }
1488
bsalomon@google.com91958362011-06-13 17:58:13 +00001489 // we don't currently apply offscreen AA to this path. Need improved
1490 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001491
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001492 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001493 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001494 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001495 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001496 target->drawNonIndexed(primitiveType, 0, vertexCount);
1497 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498}
1499
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001500///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001501
reed@google.com07f3ee12011-05-16 17:21:57 +00001502void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1503 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001504
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001505 if (path.isEmpty()) {
1506#if GR_DEBUG
1507 GrPrintf("Empty path should have been caught by canvas.\n");
1508#endif
1509 if (GrIsFillInverted(fill)) {
1510 this->drawPaint(paint);
1511 }
1512 return;
1513 }
1514
bsalomon@google.com27847de2011-02-22 20:59:41 +00001515 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001516
bsalomon@google.com289533a2011-10-27 12:34:25 +00001517 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1518
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001519 // An Assumption here is that path renderer would use some form of tweaking
1520 // the src color (either the input alpha or in the frag shader) to implement
1521 // aa. If we have some future driver-mojo path AA that can do the right
1522 // thing WRT to the blend then we'll need some query on the PR.
1523 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001524#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001525 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001526#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001527 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001528 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001529
1530 bool doOSAA = false;
1531 GrPathRenderer* pr = NULL;
1532 if (prAA) {
1533 pr = this->getPathRenderer(path, fill, true);
1534 if (NULL == pr) {
1535 prAA = false;
1536 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1537 pr = this->getPathRenderer(path, fill, false);
1538 }
1539 } else {
1540 pr = this->getPathRenderer(path, fill, false);
1541 }
1542
bsalomon@google.com30085192011-08-19 15:42:31 +00001543 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001544#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001545 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001546#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001547 return;
1548 }
1549
bsalomon@google.com289533a2011-10-27 12:34:25 +00001550 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.com39ee0ff2011-12-06 15:32:52 +00001551 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001552
bsalomon@google.com289533a2011-10-27 12:34:25 +00001553 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001554 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001555 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001556 // compute bounds as intersection of rt size, clip, and path
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001557 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001558 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001559 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001560 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001561 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001562 return;
1563 }
1564 }
reed@google.com07f3ee12011-05-16 17:21:57 +00001565 GrRect pathBounds = path.getBounds();
1566 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001567 if (NULL != translate) {
1568 pathBounds.offset(*translate);
1569 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001570 target->getDrawState().getViewMatrix().mapRect(&pathBounds,
1571 pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001572 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001573 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001574 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001575 return;
1576 }
1577 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001578 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001579 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1580 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001581 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1582 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1583 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001584 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001585 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1586 }
1587 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001588 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001589 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001590 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1591 GrRect rect;
1592 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001593 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1594 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001595 target->drawSimpleRect(rect, NULL, stageMask);
1596 }
1597 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001598 rect.iset(clipIBounds.fLeft, bound.fTop,
1599 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001600 target->drawSimpleRect(rect, NULL, stageMask);
1601 }
1602 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001603 rect.iset(bound.fRight, bound.fTop,
1604 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001605 target->drawSimpleRect(rect, NULL, stageMask);
1606 }
1607 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001608 rect.iset(clipIBounds.fLeft, bound.fBottom,
1609 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001610 target->drawSimpleRect(rect, NULL, stageMask);
1611 }
1612 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001613 return;
1614 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001615 }
1616 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001617}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001618
bsalomon@google.com27847de2011-02-22 20:59:41 +00001619////////////////////////////////////////////////////////////////////////////////
1620
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001621bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001622 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001623}
1624
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001625void GrContext::flush(int flagsBitfield) {
1626 if (kDiscard_FlushBit & flagsBitfield) {
1627 fDrawBuffer->reset();
1628 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001629 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001630 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001631 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001632 fGpu->forceRenderTargetFlush();
1633 }
1634}
1635
1636void GrContext::flushText() {
1637 if (kText_DrawCategory == fLastDrawCategory) {
1638 flushDrawBuffer();
1639 }
1640}
1641
1642void GrContext::flushDrawBuffer() {
1643#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001644 if (fDrawBuffer) {
1645 fDrawBuffer->playback(fGpu);
1646 fDrawBuffer->reset();
1647 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001648#endif
1649}
1650
bsalomon@google.com6f379512011-11-16 20:36:03 +00001651void GrContext::internalWriteTexturePixels(GrTexture* texture,
1652 int left, int top,
1653 int width, int height,
1654 GrPixelConfig config,
1655 const void* buffer,
1656 size_t rowBytes,
1657 uint32_t flags) {
1658 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001659 ASSERT_OWNED_RESOURCE(texture);
1660
bsalomon@google.com6f379512011-11-16 20:36:03 +00001661 if (!(kDontFlush_PixelOpsFlag & flags)) {
1662 this->flush();
1663 }
1664 // TODO: use scratch texture to perform conversion
1665 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1666 GrPixelConfigIsUnpremultiplied(config)) {
1667 return;
1668 }
1669
1670 fGpu->writeTexturePixels(texture, left, top, width, height,
1671 config, buffer, rowBytes);
1672}
1673
1674bool GrContext::internalReadTexturePixels(GrTexture* texture,
1675 int left, int top,
1676 int width, int height,
1677 GrPixelConfig config,
1678 void* buffer,
1679 size_t rowBytes,
1680 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001681 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001682 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001683
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001684 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001685 GrRenderTarget* target = texture->asRenderTarget();
1686 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001687 return this->internalReadRenderTargetPixels(target,
1688 left, top, width, height,
1689 config, buffer, rowBytes,
1690 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001691 } else {
1692 return false;
1693 }
1694}
1695
bsalomon@google.com6f379512011-11-16 20:36:03 +00001696bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1697 int left, int top,
1698 int width, int height,
1699 GrPixelConfig config,
1700 void* buffer,
1701 size_t rowBytes,
1702 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001703 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001704 ASSERT_OWNED_RESOURCE(target);
1705
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001706 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001707 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001708 if (NULL == target) {
1709 return false;
1710 }
1711 }
1712
1713 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1714 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1715 // not supported at this time.
1716 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1717 !GrPixelConfigIsUnpremultiplied(config)) {
1718 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001719 }
1720
bsalomon@google.com6f379512011-11-16 20:36:03 +00001721 if (!(kDontFlush_PixelOpsFlag & flags)) {
1722 this->flush();
1723 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001724
1725 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001726 bool swapRAndB = NULL != src &&
1727 fGpu->preferredReadPixelsConfig(config) ==
1728 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001729
1730 bool flipY = NULL != src &&
1731 fGpu->readPixelsWillPayForYFlip(target, left, top,
1732 width, height, config,
1733 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001734 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1735 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001736
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001737 if (NULL == src && alphaConversion) {
1738 // we should fallback to cpu conversion here. This could happen when
1739 // we were given an external render target by the client that is not
1740 // also a texture (e.g. FBO 0 in GL)
1741 return false;
1742 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001743 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001744 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001745 if (flipY || swapRAndB || alphaConversion) {
1746 GrAssert(NULL != src);
1747 if (swapRAndB) {
1748 config = GrPixelConfigSwapRAndB(config);
1749 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001750 }
1751 // Make the scratch a render target because we don't have a robust
1752 // readTexturePixels as of yet (it calls this function).
1753 const GrTextureDesc desc = {
1754 kRenderTarget_GrTextureFlagBit,
1755 kNone_GrAALevel,
1756 width, height,
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001757 config
bsalomon@google.comc4364992011-11-07 15:54:49 +00001758 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001759
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001760 // When a full readback is faster than a partial we could always make
1761 // the scratch exactly match the passed rect. However, if we see many
1762 // different size rectangles we will trash our texture cache and pay the
1763 // cost of creating and destroying many textures. So, we only request
1764 // an exact match when the caller is reading an entire RT.
1765 ScratchTexMatch match = kApprox_ScratchTexMatch;
1766 if (0 == left &&
1767 0 == top &&
1768 target->width() == width &&
1769 target->height() == height &&
1770 fGpu->fullReadPixelsIsFasterThanPartial()) {
1771 match = kExact_ScratchTexMatch;
1772 }
1773 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001774 GrTexture* texture = ast.texture();
1775 if (!texture) {
1776 return false;
1777 }
1778 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001779 GrAssert(NULL != target);
1780
1781 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001782 reset_target_state(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001783 GrDrawState* drawState = fGpu->drawState();
1784 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001785
bsalomon@google.comc4364992011-11-07 15:54:49 +00001786 GrMatrix matrix;
1787 if (flipY) {
1788 matrix.setTranslate(SK_Scalar1 * left,
1789 SK_Scalar1 * (top + height));
1790 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1791 } else {
1792 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1793 }
1794 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001795 GrSamplerState sampler;
1796 sampler.reset(GrSamplerState::kClamp_WrapMode,
1797 GrSamplerState::kNearest_Filter,
1798 matrix);
1799 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001800 drawState->setSampler(0, sampler);
1801 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001802 GrRect rect;
1803 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1804 fGpu->drawSimpleRect(rect, NULL, 0x1);
1805 left = 0;
1806 top = 0;
1807 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001808 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001809 left, top, width, height,
1810 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001811}
1812
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001813void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1814 if (NULL == src || NULL == dst) {
1815 return;
1816 }
1817 ASSERT_OWNED_RESOURCE(src);
1818
1819 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001820 reset_target_state(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001821 GrDrawState* drawState = fGpu->drawState();
1822 drawState->setRenderTarget(dst);
bsalomon@google.com97912912011-12-06 16:30:36 +00001823 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001824 GrSamplerState::kNearest_Filter);
1825 GrMatrix sampleM;
1826 sampleM.setIDiv(src->width(), src->height());
1827 sampler.setMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001828 drawState->setTexture(0, src);
1829 drawState->setSampler(0, sampler);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001830 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height());
1831 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1832}
1833
bsalomon@google.com6f379512011-11-16 20:36:03 +00001834void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1835 int left, int top,
1836 int width, int height,
1837 GrPixelConfig config,
1838 const void* buffer,
1839 size_t rowBytes,
1840 uint32_t flags) {
1841 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001842 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001843
1844 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001845 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001846 if (NULL == target) {
1847 return;
1848 }
1849 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001850
1851 // TODO: when underlying api has a direct way to do this we should use it
1852 // (e.g. glDrawPixels on desktop GL).
1853
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001854 // If the RT is also a texture and we don't have to do PM/UPM conversion
1855 // then take the texture path, which we expect to be at least as fast or
1856 // faster since it doesn't use an intermediate texture as we do below.
1857
1858#if !GR_MAC_BUILD
1859 // At least some drivers on the Mac get confused when glTexImage2D is called
1860 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1861 // determine what OS versions and/or HW is affected.
1862 if (NULL != target->asTexture() &&
1863 GrPixelConfigIsUnpremultiplied(target->config()) ==
1864 GrPixelConfigIsUnpremultiplied(config)) {
1865
1866 this->internalWriteTexturePixels(target->asTexture(),
1867 left, top, width, height,
1868 config, buffer, rowBytes, flags);
1869 return;
1870 }
1871#endif
1872
1873 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1874 GrPixelConfigSwapRAndB(config);
1875 if (swapRAndB) {
1876 config = GrPixelConfigSwapRAndB(config);
1877 }
1878
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001879 const GrTextureDesc desc = {
bsalomon@google.com5bc34f02011-12-06 14:46:34 +00001880 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001881 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001882 GrAutoScratchTexture ast(this, desc);
1883 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001884 if (NULL == texture) {
1885 return;
1886 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001887 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1888 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889
bsalomon@google.com27847de2011-02-22 20:59:41 +00001890 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001891 reset_target_state(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001892 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001893
1894 GrMatrix matrix;
1895 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001896 drawState->setViewMatrix(matrix);
1897 drawState->setRenderTarget(target);
1898 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001899
bsalomon@google.com5c638652011-07-18 19:31:59 +00001900 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com97912912011-12-06 16:30:36 +00001901 GrSamplerState sampler;
1902 sampler.reset(GrSamplerState::kClamp_WrapMode,
1903 GrSamplerState::kNearest_Filter,
1904 matrix);
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001905 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001906 drawState->setSampler(0, sampler);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001907
1908 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1909 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001910 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001911 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1912 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001913 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001914 return;
1915 }
1916 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1917 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1918}
1919////////////////////////////////////////////////////////////////////////////////
1920
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001921void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001922 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001923
1924 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1925 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001926 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001927 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001928 drawState->setSampler(s, paint.getTextureSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001929 }
1930
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001931 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001932
1933 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1934 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001935 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001936 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001937 drawState->setSampler(s, paint.getMaskSampler(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001938 }
1939
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001940 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001941
1942 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001943 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001944 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001945 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001946 }
1947 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001948 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001949 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001950 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001951 }
bsalomon@google.com3d0835b2011-12-08 16:12:03 +00001952 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001953 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001954
1955 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1956 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1957 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001958}
1959
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001960GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001961 DrawCategory category) {
1962 if (category != fLastDrawCategory) {
1963 flushDrawBuffer();
1964 fLastDrawCategory = category;
1965 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001966 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001967 GrDrawTarget* target = fGpu;
1968 switch (category) {
1969 case kText_DrawCategory:
1970#if DEFER_TEXT_RENDERING
1971 target = fDrawBuffer;
1972 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1973#else
1974 target = fGpu;
1975#endif
1976 break;
1977 case kUnbuffered_DrawCategory:
1978 target = fGpu;
1979 break;
1980 case kBuffered_DrawCategory:
1981 target = fDrawBuffer;
1982 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1983 break;
1984 }
1985 return target;
1986}
1987
bsalomon@google.com289533a2011-10-27 12:34:25 +00001988GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1989 GrPathFill fill,
1990 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001991 if (NULL == fPathRendererChain) {
1992 fPathRendererChain =
1993 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1994 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001995 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1996 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001997}
1998
bsalomon@google.com27847de2011-02-22 20:59:41 +00001999////////////////////////////////////////////////////////////////////////////////
2000
bsalomon@google.com27847de2011-02-22 20:59:41 +00002001void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002002 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002003 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002004 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002005}
2006
2007GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002008 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002009}
2010
2011const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002012 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002013}
2014
2015const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002016 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00002017}
2018
2019void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002020 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002021}
2022
2023void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002024 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002025}
2026
2027static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
2028 intptr_t mask = 1 << shift;
2029 if (pred) {
2030 bits |= mask;
2031 } else {
2032 bits &= ~mask;
2033 }
2034 return bits;
2035}
2036
2037void GrContext::resetStats() {
2038 fGpu->resetStats();
2039}
2040
bsalomon@google.com05ef5102011-05-02 21:14:59 +00002041const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002042 return fGpu->getStats();
2043}
2044
2045void GrContext::printStats() const {
2046 fGpu->printStats();
2047}
2048
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002049GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002050 fGpu = gpu;
2051 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002052 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002053
bsalomon@google.com30085192011-08-19 15:42:31 +00002054 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002055
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002056 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2057 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002058 fFontCache = new GrFontCache(fGpu);
2059
2060 fLastDrawCategory = kUnbuffered_DrawCategory;
2061
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002062 fDrawBuffer = NULL;
2063 fDrawBufferVBAllocPool = NULL;
2064 fDrawBufferIBAllocPool = NULL;
2065
bsalomon@google.com205d4602011-04-25 12:43:45 +00002066 fAAFillRectIndexBuffer = NULL;
2067 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002068
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002069 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2070 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002071 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2072 }
2073 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002074
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002075 this->setupDrawBuffer();
2076}
2077
2078void GrContext::setupDrawBuffer() {
2079
2080 GrAssert(NULL == fDrawBuffer);
2081 GrAssert(NULL == fDrawBufferVBAllocPool);
2082 GrAssert(NULL == fDrawBufferIBAllocPool);
2083
bsalomon@google.com27847de2011-02-22 20:59:41 +00002084#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002085 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002086 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002087 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2088 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002089 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002090 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002091 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002092 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2093
bsalomon@google.com471d4712011-08-23 15:45:25 +00002094 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2095 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002096 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002097#endif
2098
2099#if BATCH_RECT_TO_RECT
2100 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2101#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002102}
2103
bsalomon@google.com27847de2011-02-22 20:59:41 +00002104GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2105 GrDrawTarget* target;
2106#if DEFER_TEXT_RENDERING
2107 target = prepareToDraw(paint, kText_DrawCategory);
2108#else
2109 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2110#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002111 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002112 return target;
2113}
2114
2115const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2116 return fGpu->getQuadIndexBuffer();
2117}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002118
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002119void GrContext::convolveInX(GrTexture* texture,
2120 const SkRect& rect,
2121 const float* kernel,
2122 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002123 ASSERT_OWNED_RESOURCE(texture);
2124
bsalomon@google.com99621082011-11-15 16:47:16 +00002125 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002126 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2127}
2128
2129void GrContext::convolveInY(GrTexture* texture,
2130 const SkRect& rect,
2131 const float* kernel,
2132 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002133 ASSERT_OWNED_RESOURCE(texture);
2134
bsalomon@google.com99621082011-11-15 16:47:16 +00002135 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002136 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2137}
2138
2139void GrContext::convolve(GrTexture* texture,
2140 const SkRect& rect,
2141 float imageIncrement[2],
2142 const float* kernel,
2143 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002144 ASSERT_OWNED_RESOURCE(texture);
2145
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002146 GrDrawTarget::AutoStateRestore asr(fGpu);
2147 GrMatrix sampleM;
bsalomon@google.com97912912011-12-06 16:30:36 +00002148 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002149 GrSamplerState::kConvolution_Filter);
2150 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002151 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002152 sampler.setMatrix(sampleM);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002153 GrDrawState* drawState = fGpu->drawState();
2154 drawState->setSampler(0, sampler);
2155 drawState->setViewMatrix(GrMatrix::I());
2156 drawState->setTexture(0, texture);
2157 drawState->setAlpha(0xFF);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002158 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002159 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2160}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002161
2162///////////////////////////////////////////////////////////////////////////////