blob: c69c421ab892e0d29f5cc01e6cbc897e4b9afcf8 [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.
220void reset_target_state(GrDrawTarget* target){
221 target->setViewMatrix(GrMatrix::I());
222 target->setColorFilter(0, SkXfermode::kDst_Mode);
223 target->disableState(GrDrawTarget::kDither_StateBit |
224 GrDrawTarget::kHWAntialias_StateBit |
225 GrDrawTarget::kClip_StateBit |
226 GrDrawTarget::kNoColorWrites_StateBit |
227 GrDrawTarget::kEdgeAAConcave_StateBit);
228 target->setEdgeAAData(NULL, 0);
229 target->disableStencil();
230 target->setAlpha(0xFF);
231 target->setBlendFunc(kOne_BlendCoeff,
232 kZero_BlendCoeff);
233 target->setFirstCoverageStage(GrDrawState::kNumStages);
234 target->setDrawFace(GrDrawState::kBoth_DrawFace);
235}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000236}
237
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000238GrContext::TextureCacheEntry GrContext::findAndLockTexture(TextureKey key,
239 int width,
240 int height,
241 const GrSamplerState& sampler) {
242 uint32_t v[4];
243 gen_texture_key_values(fGpu, sampler, key, width, height, false, v);
244 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000245 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
246 GrResourceCache::kNested_LockType));
247}
248
249GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000250 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000251 uint32_t v[4];
252 gen_stencil_key_values(sb, v);
253 GrResourceKey resourceKey(v);
254 return fTextureCache->createAndLock(resourceKey, sb);
255}
256
257GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
258 int sampleCnt) {
259 uint32_t v[4];
260 gen_stencil_key_values(width, height, sampleCnt, v);
261 GrResourceKey resourceKey(v);
262 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
263 GrResourceCache::kSingle_LockType);
264 if (NULL != entry) {
265 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
266 return sb;
267 } else {
268 return NULL;
269 }
270}
271
272void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000273 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000274 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000275}
276
277static void stretchImage(void* dst,
278 int dstW,
279 int dstH,
280 void* src,
281 int srcW,
282 int srcH,
283 int bpp) {
284 GrFixed dx = (srcW << 16) / dstW;
285 GrFixed dy = (srcH << 16) / dstH;
286
287 GrFixed y = dy >> 1;
288
289 int dstXLimit = dstW*bpp;
290 for (int j = 0; j < dstH; ++j) {
291 GrFixed x = dx >> 1;
292 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
293 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
294 for (int i = 0; i < dstXLimit; i += bpp) {
295 memcpy((uint8_t*) dstRow + i,
296 (uint8_t*) srcRow + (x>>16)*bpp,
297 bpp);
298 x += dx;
299 }
300 y += dy;
301 }
302}
303
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000304GrContext::TextureCacheEntry GrContext::createAndLockTexture(TextureKey key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000305 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000306 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000307 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000308 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000309
310#if GR_DUMP_TEXTURE_UPLOAD
311 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
312#endif
313
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000314 TextureCacheEntry entry;
315 uint32_t v[4];
316 bool special = gen_texture_key_values(fGpu, sampler, key,
317 desc.fWidth, desc.fHeight, false, v);
318 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000319
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000320 if (special) {
321 TextureCacheEntry clampEntry =
322 findAndLockTexture(key, desc.fWidth, desc.fHeight,
323 GrSamplerState::ClampNoFilter());
324
325 if (NULL == clampEntry.texture()) {
326 clampEntry = createAndLockTexture(key,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000327 GrSamplerState::ClampNoFilter(),
328 desc, srcData, rowBytes);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000329 GrAssert(NULL != clampEntry.texture());
330 if (NULL == clampEntry.texture()) {
331 return entry;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000332 }
333 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000334 GrTextureDesc rtDesc = desc;
335 rtDesc.fFlags = rtDesc.fFlags |
336 kRenderTarget_GrTextureFlagBit |
337 kNoStencil_GrTextureFlagBit;
bsalomon@google.com99621082011-11-15 16:47:16 +0000338 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64));
339 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000340
341 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
342
343 if (NULL != texture) {
344 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000345 reset_target_state(fGpu);
346
bsalomon@google.com27847de2011-02-22 20:59:41 +0000347 fGpu->setRenderTarget(texture->asRenderTarget());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000348 fGpu->setTexture(0, clampEntry.texture());
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000349
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000350 GrSamplerState::Filter filter;
351 // if filtering is not desired then we want to ensure all
352 // texels in the resampled image are copies of texels from
353 // the original.
354 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
355 filter = GrSamplerState::kNearest_Filter;
356 } else {
357 filter = GrSamplerState::kBilinear_Filter;
358 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000359 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
360 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000361 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000362 fGpu->setSamplerState(0, stretchSampler);
363
364 static const GrVertexLayout layout =
365 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
366 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
367
368 if (arg.succeeded()) {
369 GrPoint* verts = (GrPoint*) arg.vertices();
370 verts[0].setIRectFan(0, 0,
371 texture->width(),
372 texture->height(),
373 2*sizeof(GrPoint));
374 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
375 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
376 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000377 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000378 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000379 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000380 } else {
381 // TODO: Our CPU stretch doesn't filter. But we create separate
382 // stretched textures when the sampler state is either filtered or
383 // not. Either implement filtered stretch blit on CPU or just create
384 // one when FBO case fails.
385
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000386 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000387 // no longer need to clamp at min RT size.
388 rtDesc.fWidth = GrNextPow2(desc.fWidth);
389 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000390 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000391 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000392 rtDesc.fWidth *
393 rtDesc.fHeight);
394 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
395 srcData, desc.fWidth, desc.fHeight, bpp);
396
397 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
398
399 GrTexture* texture = fGpu->createTexture(rtDesc,
400 stretchedPixels.get(),
401 stretchedRowBytes);
402 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000404 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000405 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000406
407 } else {
408 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
409 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000410 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000411 }
412 }
413 return entry;
414}
415
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000416namespace {
417inline void gen_scratch_tex_key_values(const GrGpu* gpu,
418 const GrTextureDesc& desc,
419 uint32_t v[4]) {
420 // Instead of a client-provided key of the texture contents
421 // we create a key of from the descriptor.
422 GrContext::TextureKey descKey = desc.fAALevel |
423 (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000424 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000425 // this code path isn't friendly to tiling with NPOT restricitons
426 // We just pass ClampNoFilter()
427 gen_texture_key_values(gpu, GrSamplerState::ClampNoFilter(), descKey,
428 desc.fWidth, desc.fHeight, true, v);
429}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000430}
431
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000432GrContext::TextureCacheEntry GrContext::lockScratchTexture(
433 const GrTextureDesc& inDesc,
434 ScratchTexMatch match) {
435
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000436 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000437 if (kExact_ScratchTexMatch != match) {
438 // bin by pow2 with a reasonable min
439 static const int MIN_SIZE = 256;
440 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
441 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
442 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000443
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000444 uint32_t p0 = desc.fConfig;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000445 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
446
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000447 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000448 int origWidth = desc.fWidth;
449 int origHeight = desc.fHeight;
450 bool doubledW = false;
451 bool doubledH = false;
452
453 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000454 uint32_t v[4];
455 gen_scratch_tex_key_values(fGpu, desc, v);
456 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000457 entry = fTextureCache->findAndLock(key,
458 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000459 // if we miss, relax the fit of the flags...
460 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000461 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000462 break;
463 }
464 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
465 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
466 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
467 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
468 } else if (!doubledW) {
469 desc.fFlags = inDesc.fFlags;
470 desc.fWidth *= 2;
471 doubledW = true;
472 } else if (!doubledH) {
473 desc.fFlags = inDesc.fFlags;
474 desc.fWidth = origWidth;
475 desc.fHeight *= 2;
476 doubledH = true;
477 } else {
478 break;
479 }
480
481 } while (true);
482
483 if (NULL == entry) {
484 desc.fFlags = inDesc.fFlags;
485 desc.fWidth = origWidth;
486 desc.fHeight = origHeight;
487 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
488 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000489 uint32_t v[4];
490 gen_scratch_tex_key_values(fGpu, desc, v);
491 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000492 entry = fTextureCache->createAndLock(key, texture);
493 }
494 }
495
496 // If the caller gives us the same desc/sampler twice we don't want
497 // to return the same texture the second time (unless it was previously
498 // released). So we detach the entry from the cache and reattach at release.
499 if (NULL != entry) {
500 fTextureCache->detach(entry);
501 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000502 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000503}
504
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000505void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000506 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000507 // If this is a scratch texture we detached it from the cache
508 // while it was locked (to avoid two callers simultaneously getting
509 // the same texture).
510 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
511 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000512 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000513 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000514 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000515}
516
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000517GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000518 void* srcData,
519 size_t rowBytes) {
520 return fGpu->createTexture(desc, srcData, rowBytes);
521}
522
523void GrContext::getTextureCacheLimits(int* maxTextures,
524 size_t* maxTextureBytes) const {
525 fTextureCache->getLimits(maxTextures, maxTextureBytes);
526}
527
528void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
529 fTextureCache->setLimits(maxTextures, maxTextureBytes);
530}
531
bsalomon@google.com91958362011-06-13 17:58:13 +0000532int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000533 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000534}
535
536int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000537 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000538}
539
540///////////////////////////////////////////////////////////////////////////////
541
bsalomon@google.come269f212011-11-07 13:29:52 +0000542GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
543 return fGpu->createPlatformTexture(desc);
544}
545
546GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
547 return fGpu->createPlatformRenderTarget(desc);
548}
549
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000550GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
551 // validate flags here so that GrGpu subclasses don't have to check
552 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
553 0 != desc.fRenderTargetFlags) {
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000554 return NULL;
555 }
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000556 if (desc.fSampleCnt &&
557 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
bsalomon@google.com973b8792011-09-02 17:28:06 +0000558 return NULL;
bsalomon@google.com5bfc2172011-07-29 20:29:05 +0000559 }
560 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
561 desc.fSampleCnt &&
562 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
563 return NULL;
564 }
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000565 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000566}
567
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000568///////////////////////////////////////////////////////////////////////////////
569
bsalomon@google.com27847de2011-02-22 20:59:41 +0000570bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000571 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000572 const GrDrawTarget::Caps& caps = fGpu->getCaps();
573 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000574 return false;
575 }
576
bsalomon@google.com27847de2011-02-22 20:59:41 +0000577 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
578
579 if (!isPow2) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000580 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
581 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000582 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000583 return false;
584 }
585 }
586 return true;
587}
588
589////////////////////////////////////////////////////////////////////////////////
590
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000591const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
592
bsalomon@google.com27847de2011-02-22 20:59:41 +0000593void GrContext::setClip(const GrClip& clip) {
594 fGpu->setClip(clip);
595 fGpu->enableState(GrDrawTarget::kClip_StateBit);
596}
597
598void GrContext::setClip(const GrIRect& rect) {
599 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000600 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000601 fGpu->setClip(clip);
602}
603
604////////////////////////////////////////////////////////////////////////////////
605
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000606void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000607 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000608 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000609}
610
611void GrContext::drawPaint(const GrPaint& paint) {
612 // set rect to be big enough to fill the space, but not super-huge, so we
613 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000614 GrRect r;
615 r.setLTRB(0, 0,
616 GrIntToScalar(getRenderTarget()->width()),
617 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000618 GrAutoMatrix am;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000619 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000620 SkTLazy<GrPaint> tmpPaint;
621 const GrPaint* p = &paint;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000622 // We attempt to map r by the inverse matrix and draw that. mapRect will
623 // map the four corners and bound them with a new rect. This will not
624 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000625 if (!this->getMatrix().hasPerspective()) {
626 if (!fGpu->getViewInverse(&inverse)) {
627 GrPrintf("Could not invert matrix");
628 return;
629 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000630 inverse.mapRect(&r);
631 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000632 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
633 if (!fGpu->getViewInverse(&inverse)) {
634 GrPrintf("Could not invert matrix");
635 return;
636 }
637 tmpPaint.set(paint);
638 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
639 p = tmpPaint.get();
640 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000641 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000642 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000643 // by definition this fills the entire clip, no need for AA
644 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000645 if (!tmpPaint.isValid()) {
646 tmpPaint.set(paint);
647 p = tmpPaint.get();
648 }
649 GrAssert(p == tmpPaint.get());
650 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000651 }
652 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000653}
654
bsalomon@google.com205d4602011-04-25 12:43:45 +0000655////////////////////////////////////////////////////////////////////////////////
656
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000657namespace {
658inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
659 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
660}
661}
662
bsalomon@google.com91958362011-06-13 17:58:13 +0000663struct GrContext::OffscreenRecord {
bsalomon@google.com91958362011-06-13 17:58:13 +0000664 enum Downsample {
665 k4x4TwoPass_Downsample,
666 k4x4SinglePass_Downsample,
667 kFSAA_Downsample
668 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000669 int fTileSizeX;
670 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000671 int fTileCountX;
672 int fTileCountY;
673 int fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000674 GrAutoScratchTexture fOffscreen0;
675 GrAutoScratchTexture fOffscreen1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000676 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000677 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000678};
679
bsalomon@google.com471d4712011-08-23 15:45:25 +0000680bool GrContext::doOffscreenAA(GrDrawTarget* target,
bsalomon@google.com471d4712011-08-23 15:45:25 +0000681 bool isHairLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000682#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000683 return false;
684#else
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000685 // Line primitves are always rasterized as 1 pixel wide.
686 // Super-sampling would make them too thin but MSAA would be OK.
687 if (isHairLines &&
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000688 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000689 return false;
690 }
691 if (target->getRenderTarget()->isMultisampled()) {
692 return false;
693 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000694 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000695#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +0000696 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000697#endif
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000698 return false;
699 }
700 return true;
701#endif
702}
703
bsalomon@google.com91958362011-06-13 17:58:13 +0000704bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000705 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000706 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000707 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000708 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000709
710 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000711
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000712 GrAssert(NULL == record->fOffscreen0.texture());
713 GrAssert(NULL == record->fOffscreen1.texture());
bsalomon@google.com91958362011-06-13 17:58:13 +0000714 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000715
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000716 int boundW = boundRect.width();
717 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000718
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000719 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000720
721 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
722 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
723
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000724 if (requireStencil) {
725 desc.fFlags = kRenderTarget_GrTextureFlagBit;
726 } else {
727 desc.fFlags = kRenderTarget_GrTextureFlagBit |
728 kNoStencil_GrTextureFlagBit;
729 }
730
bsalomon@google.comc4364992011-11-07 15:54:49 +0000731 desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000732
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000733 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000734 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000735 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000736 desc.fAALevel = kMed_GrAALevel;
737 } else {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000738 record->fDownsample = fGpu->getCaps().fShaderSupport ?
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000739 OffscreenRecord::k4x4SinglePass_Downsample :
740 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000741 record->fScale = OFFSCREEN_SSAA_SCALE;
742 // both downsample paths assume this
743 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000744 desc.fAALevel = kNone_GrAALevel;
745 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000746
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000747 desc.fWidth *= record->fScale;
748 desc.fHeight *= record->fScale;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000749 record->fOffscreen0.set(this, desc);
750 if (NULL == record->fOffscreen0.texture()) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000751 return false;
752 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000753 // the approximate lookup might have given us some slop space, might as well
754 // use it when computing the tiles size.
755 // these are scale values, will adjust after considering
756 // the possible second offscreen.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000757 record->fTileSizeX = record->fOffscreen0.texture()->width();
758 record->fTileSizeY = record->fOffscreen0.texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000759
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000760 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000761 desc.fWidth /= 2;
762 desc.fHeight /= 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000763 record->fOffscreen1.set(this, desc);
764 if (NULL == record->fOffscreen1.texture()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000765 return false;
766 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000767 record->fTileSizeX = GrMin(record->fTileSizeX,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000768 2 * record->fOffscreen0.texture()->width());
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000769 record->fTileSizeY = GrMin(record->fTileSizeY,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000770 2 * record->fOffscreen0.texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000771 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000772 record->fTileSizeX /= record->fScale;
773 record->fTileSizeY /= record->fScale;
774
775 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
776 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
777
tomhudson@google.com237a4612011-07-19 15:44:00 +0000778 record->fClip = target->getClip();
779
bsalomon@google.com91958362011-06-13 17:58:13 +0000780 target->saveCurrentDrawState(&record->fSavedState);
781 return true;
782}
783
784void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
785 const GrIRect& boundRect,
786 int tileX, int tileY,
787 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000788
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000789 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000790 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000791
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000792 GrPaint tempPaint;
793 tempPaint.reset();
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000794 this->setPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795 target->setRenderTarget(offRT0);
bsalomon@google.com289533a2011-10-27 12:34:25 +0000796#if PREFER_MSAA_OFFSCREEN_AA
797 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
798#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000799
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000800 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000801 int left = boundRect.fLeft + tileX * record->fTileSizeX;
802 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000803 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000804 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000805 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000806 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000807 target->postConcatViewMatrix(scaleM);
808
bsalomon@google.com91958362011-06-13 17:58:13 +0000809 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000810 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000811 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000812 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000813 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
814 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000815 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000816#if 0
817 // visualize tile boundaries by setting edges of offscreen to white
818 // and interior to tranparent. black.
819 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000820
bsalomon@google.com91958362011-06-13 17:58:13 +0000821 static const int gOffset = 2;
822 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
823 record->fScale * w - gOffset,
824 record->fScale * h - gOffset);
825 target->clear(&clear2, 0x0);
826#else
827 target->clear(&clear, 0x0);
828#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000829}
830
bsalomon@google.com91958362011-06-13 17:58:13 +0000831void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000832 const GrPaint& paint,
833 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000834 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000835 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000836 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000837 GrAssert(NULL != record->fOffscreen0.texture());
bsalomon@google.comee435122011-07-01 14:57:55 +0000838 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000839 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000840 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
841 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000842 tileRect.fRight = (tileX == record->fTileCountX-1) ?
843 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000844 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000845 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
846 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000847 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000848
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000849 GrSamplerState::Filter filter;
850 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
851 filter = GrSamplerState::k4x4Downsample_Filter;
852 } else {
853 filter = GrSamplerState::kBilinear_Filter;
854 }
855
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000856 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000857 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000858 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000859
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000860 GrTexture* src = record->fOffscreen0.texture();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000861 int scale;
862
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000863 enum {
864 kOffscreenStage = GrPaint::kTotalStages,
865 };
866
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000867 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000868 GrAssert(NULL != record->fOffscreen1.texture());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000869 scale = 2;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000870 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000871
872 // Do 2x2 downsample from first to second
873 target->setTexture(kOffscreenStage, src);
874 target->setRenderTarget(dst);
875 target->setViewMatrix(GrMatrix::I());
876 sampleM.setScale(scale * GR_Scalar1 / src->width(),
877 scale * GR_Scalar1 / src->height());
878 sampler.setMatrix(sampleM);
879 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000880 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()),
881 SkIntToScalar(scale * tileRect.height()));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000882 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
883
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000884 src = record->fOffscreen1.texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000885 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000886 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000887 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000888 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000889 } else {
890 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
891 record->fDownsample);
892 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000893 }
894
bsalomon@google.com91958362011-06-13 17:58:13 +0000895 // setup for draw back to main RT, we use the original
896 // draw state setup by the caller plus an additional coverage
897 // stage to handle the AA resolve. Also, we use an identity
898 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000899 int stageMask = paint.getActiveStageMask();
900
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000901 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000902 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000903
904 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000905 GrMatrix invVM;
906 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000907 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000908 }
909 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000910 // This is important when tiling, otherwise second tile's
911 // pass 1 view matrix will be incorrect.
912 GrDrawTarget::AutoViewMatrixRestore avmr(target);
913
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000914 target->setViewMatrix(GrMatrix::I());
915
916 target->setTexture(kOffscreenStage, src);
917 sampleM.setScale(scale * GR_Scalar1 / src->width(),
918 scale * GR_Scalar1 / src->height());
919 sampler.setMatrix(sampleM);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000920 sampleM.setTranslate(SkIntToScalar(-tileRect.fLeft),
921 SkIntToScalar(-tileRect.fTop));
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000922 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000923 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000924
reed@google.com20efde72011-05-09 17:00:02 +0000925 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000926 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000927 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000928 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000929}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000930
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000931void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
932 GrPathRenderer* pr,
933 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000934 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000935}
936
937////////////////////////////////////////////////////////////////////////////////
938
bsalomon@google.com27847de2011-02-22 20:59:41 +0000939/* create a triangle strip that strokes the specified triangle. There are 8
940 unique vertices, but we repreat the last 2 to close up. Alternatively we
941 could use an indices array, and then only send 8 verts, but not sure that
942 would be faster.
943 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000944static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000945 GrScalar width) {
946 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000947 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000948
949 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
950 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
951 verts[2].set(rect.fRight - rad, rect.fTop + rad);
952 verts[3].set(rect.fRight + rad, rect.fTop - rad);
953 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
954 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
955 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
956 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
957 verts[8] = verts[0];
958 verts[9] = verts[1];
959}
960
bsalomon@google.com205d4602011-04-25 12:43:45 +0000961static void setInsetFan(GrPoint* pts, size_t stride,
962 const GrRect& r, GrScalar dx, GrScalar dy) {
963 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
964}
965
966static const uint16_t gFillAARectIdx[] = {
967 0, 1, 5, 5, 4, 0,
968 1, 2, 6, 6, 5, 1,
969 2, 3, 7, 7, 6, 2,
970 3, 0, 4, 4, 7, 3,
971 4, 5, 6, 6, 7, 4,
972};
973
974int GrContext::aaFillRectIndexCount() const {
975 return GR_ARRAY_COUNT(gFillAARectIdx);
976}
977
978GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
979 if (NULL == fAAFillRectIndexBuffer) {
980 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
981 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000982 if (NULL != fAAFillRectIndexBuffer) {
983 #if GR_DEBUG
984 bool updated =
985 #endif
986 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
987 sizeof(gFillAARectIdx));
988 GR_DEBUGASSERT(updated);
989 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000990 }
991 return fAAFillRectIndexBuffer;
992}
993
994static const uint16_t gStrokeAARectIdx[] = {
995 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
996 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
997 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
998 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
999
1000 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
1001 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
1002 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
1003 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
1004
1005 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
1006 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
1007 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
1008 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
1009};
1010
1011int GrContext::aaStrokeRectIndexCount() const {
1012 return GR_ARRAY_COUNT(gStrokeAARectIdx);
1013}
1014
1015GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
1016 if (NULL == fAAStrokeRectIndexBuffer) {
1017 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
1018 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001019 if (NULL != fAAStrokeRectIndexBuffer) {
1020 #if GR_DEBUG
1021 bool updated =
1022 #endif
1023 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
1024 sizeof(gStrokeAARectIdx));
1025 GR_DEBUGASSERT(updated);
1026 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001027 }
1028 return fAAStrokeRectIndexBuffer;
1029}
1030
bsalomon@google.coma3108262011-10-10 14:08:47 +00001031static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
1032 bool useCoverage) {
1033 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +00001034 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001035 if (NULL != target->getTexture(s)) {
1036 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
1037 }
1038 }
1039 if (useCoverage) {
1040 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
1041 } else {
1042 layout |= GrDrawTarget::kColor_VertexLayoutBit;
1043 }
1044 return layout;
1045}
1046
bsalomon@google.com205d4602011-04-25 12:43:45 +00001047void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001048 const GrRect& devRect,
1049 bool useVertexCoverage) {
1050 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001051
1052 size_t vsize = GrDrawTarget::VertexSize(layout);
1053
1054 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001055 if (!geo.succeeded()) {
1056 GrPrintf("Failed to get space for vertices!\n");
1057 return;
1058 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001059 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
1060 if (NULL == indexBuffer) {
1061 GrPrintf("Failed to create index buffer!\n");
1062 return;
1063 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001064
1065 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1066
1067 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1068 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1069
1070 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
1071 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
1072
1073 verts += sizeof(GrPoint);
1074 for (int i = 0; i < 4; ++i) {
1075 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1076 }
1077
bsalomon@google.coma3108262011-10-10 14:08:47 +00001078 GrColor innerColor;
1079 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001080 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001081 } else {
1082 innerColor = target->getColor();
1083 }
1084
bsalomon@google.com205d4602011-04-25 12:43:45 +00001085 verts += 4 * vsize;
1086 for (int i = 0; i < 4; ++i) {
1087 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1088 }
1089
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001090 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001091
1092 target->drawIndexed(kTriangles_PrimitiveType, 0,
1093 0, 8, this->aaFillRectIndexCount());
1094}
1095
bsalomon@google.coma3108262011-10-10 14:08:47 +00001096void GrContext::strokeAARect(GrDrawTarget* target,
1097 const GrRect& devRect,
1098 const GrVec& devStrokeSize,
1099 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001100 const GrScalar& dx = devStrokeSize.fX;
1101 const GrScalar& dy = devStrokeSize.fY;
1102 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
1103 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
1104
bsalomon@google.com205d4602011-04-25 12:43:45 +00001105 GrScalar spare;
1106 {
1107 GrScalar w = devRect.width() - dx;
1108 GrScalar h = devRect.height() - dy;
1109 spare = GrMin(w, h);
1110 }
1111
1112 if (spare <= 0) {
1113 GrRect r(devRect);
1114 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +00001115 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001116 return;
1117 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001118 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001119 size_t vsize = GrDrawTarget::VertexSize(layout);
1120
1121 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001122 if (!geo.succeeded()) {
1123 GrPrintf("Failed to get space for vertices!\n");
1124 return;
1125 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001126 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
1127 if (NULL == indexBuffer) {
1128 GrPrintf("Failed to create index buffer!\n");
1129 return;
1130 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001131
1132 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
1133
1134 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
1135 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
1136 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
1137 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1138
1139 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1140 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1141 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1142 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1143
1144 verts += sizeof(GrPoint);
1145 for (int i = 0; i < 4; ++i) {
1146 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1147 }
1148
bsalomon@google.coma3108262011-10-10 14:08:47 +00001149 GrColor innerColor;
1150 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +00001151 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001152 } else {
1153 innerColor = target->getColor();
1154 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001155 verts += 4 * vsize;
1156 for (int i = 0; i < 8; ++i) {
1157 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1158 }
1159
1160 verts += 8 * vsize;
1161 for (int i = 0; i < 8; ++i) {
1162 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1163 }
1164
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +00001165 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001166 target->drawIndexed(kTriangles_PrimitiveType,
1167 0, 0, 16, aaStrokeRectIndexCount());
1168}
1169
reed@google.com20efde72011-05-09 17:00:02 +00001170/**
1171 * Returns true if the rects edges are integer-aligned.
1172 */
1173static bool isIRect(const GrRect& r) {
1174 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1175 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1176}
1177
bsalomon@google.com205d4602011-04-25 12:43:45 +00001178static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001179 const GrRect& rect,
1180 GrScalar width,
1181 const GrMatrix* matrix,
1182 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001183 GrRect* devRect,
1184 bool* useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001185 // we use a simple alpha ramp to do aa on axis-aligned rects
1186 // do AA with alpha ramp if the caller requested AA, the rect
bsalomon@google.com289533a2011-10-27 12:34:25 +00001187 // will be axis-aligned, and the rect won't land on integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001188
bsalomon@google.coma3108262011-10-10 14:08:47 +00001189 // we are keeping around the "tweak the alpha" trick because
1190 // it is our only hope for the fixed-pipe implementation.
1191 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +00001192 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +00001193 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001194 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001195 if (target->getCaps().fSupportPerVertexCoverage) {
1196 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001197#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001198 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001199#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +00001200 return false;
1201 } else {
1202 *useVertexCoverage = true;
1203 }
1204 } else {
1205 GrPrintf("Rect AA dropped because no support for coverage.\n");
1206 return false;
1207 }
bsalomon@google.com205d4602011-04-25 12:43:45 +00001208 }
1209
1210 if (target->getRenderTarget()->isMultisampled()) {
1211 return false;
1212 }
1213
bsalomon@google.com471d4712011-08-23 15:45:25 +00001214 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001215 return false;
1216 }
1217
1218 if (!target->getViewMatrix().preservesAxisAlignment()) {
1219 return false;
1220 }
1221
1222 if (NULL != matrix &&
1223 !matrix->preservesAxisAlignment()) {
1224 return false;
1225 }
1226
1227 *combinedMatrix = target->getViewMatrix();
1228 if (NULL != matrix) {
1229 combinedMatrix->preConcat(*matrix);
1230 GrAssert(combinedMatrix->preservesAxisAlignment());
1231 }
1232
1233 combinedMatrix->mapRect(devRect, rect);
1234 devRect->sort();
1235
1236 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001237 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001238 } else {
1239 return true;
1240 }
1241}
1242
bsalomon@google.com27847de2011-02-22 20:59:41 +00001243void GrContext::drawRect(const GrPaint& paint,
1244 const GrRect& rect,
1245 GrScalar width,
1246 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001247 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001248
1249 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001250 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001251
bsalomon@google.com205d4602011-04-25 12:43:45 +00001252 GrRect devRect = rect;
1253 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +00001254 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +00001255 bool needAA = paint.fAntiAlias &&
1256 !this->getRenderTarget()->isMultisampled();
1257 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
1258 &combinedMatrix, &devRect,
1259 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001260
1261 if (doAA) {
1262 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001263 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001264 GrMatrix inv;
1265 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001266 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001267 }
1268 }
1269 target->setViewMatrix(GrMatrix::I());
1270 if (width >= 0) {
1271 GrVec strokeSize;;
1272 if (width > 0) {
1273 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001274 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001275 strokeSize.setAbs(strokeSize);
1276 } else {
1277 strokeSize.set(GR_Scalar1, GR_Scalar1);
1278 }
bsalomon@google.coma3108262011-10-10 14:08:47 +00001279 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001280 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +00001281 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001282 }
1283 return;
1284 }
1285
bsalomon@google.com27847de2011-02-22 20:59:41 +00001286 if (width >= 0) {
1287 // TODO: consider making static vertex buffers for these cases.
1288 // Hairline could be done by just adding closing vertex to
1289 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001290 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1291
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292 static const int worstCaseVertCount = 10;
1293 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1294
1295 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001296 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001297 return;
1298 }
1299
1300 GrPrimitiveType primType;
1301 int vertCount;
1302 GrPoint* vertex = geo.positions();
1303
1304 if (width > 0) {
1305 vertCount = 10;
1306 primType = kTriangleStrip_PrimitiveType;
1307 setStrokeRectStrip(vertex, rect, width);
1308 } else {
1309 // hairline
1310 vertCount = 5;
1311 primType = kLineStrip_PrimitiveType;
1312 vertex[0].set(rect.fLeft, rect.fTop);
1313 vertex[1].set(rect.fRight, rect.fTop);
1314 vertex[2].set(rect.fRight, rect.fBottom);
1315 vertex[3].set(rect.fLeft, rect.fBottom);
1316 vertex[4].set(rect.fLeft, rect.fTop);
1317 }
1318
1319 GrDrawTarget::AutoViewMatrixRestore avmr;
1320 if (NULL != matrix) {
1321 avmr.set(target);
1322 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001323 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324 }
1325
1326 target->drawNonIndexed(primType, 0, vertCount);
1327 } else {
1328 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001329 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001330 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1331 if (NULL == sqVB) {
1332 GrPrintf("Failed to create static rect vb.\n");
1333 return;
1334 }
1335 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001336 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1337 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001338 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001339 0, rect.height(), rect.fTop,
1340 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001341
1342 if (NULL != matrix) {
1343 m.postConcat(*matrix);
1344 }
1345
1346 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001347 target->preConcatSamplerMatrices(stageMask, m);
1348
bsalomon@google.com27847de2011-02-22 20:59:41 +00001349 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1350 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001351 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001352 #endif
1353 }
1354}
1355
1356void GrContext::drawRectToRect(const GrPaint& paint,
1357 const GrRect& dstRect,
1358 const GrRect& srcRect,
1359 const GrMatrix* dstMatrix,
1360 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001361 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001362
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001363 // srcRect refers to paint's first texture
1364 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001365 drawRect(paint, dstRect, -1, dstMatrix);
1366 return;
1367 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001368
bsalomon@google.com27847de2011-02-22 20:59:41 +00001369 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1370
1371#if GR_STATIC_RECT_VB
1372 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001373
1374 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001375 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1376
1377 GrMatrix m;
1378
1379 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1380 0, dstRect.height(), dstRect.fTop,
1381 0, 0, GrMatrix::I()[8]);
1382 if (NULL != dstMatrix) {
1383 m.postConcat(*dstMatrix);
1384 }
1385 target->preConcatViewMatrix(m);
1386
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001387 // srcRect refers to first stage
1388 int otherStageMask = paint.getActiveStageMask() &
1389 (~(1 << GrPaint::kFirstTextureStage));
1390 if (otherStageMask) {
1391 target->preConcatSamplerMatrices(otherStageMask, m);
1392 }
1393
bsalomon@google.com27847de2011-02-22 20:59:41 +00001394 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1395 0, srcRect.height(), srcRect.fTop,
1396 0, 0, GrMatrix::I()[8]);
1397 if (NULL != srcMatrix) {
1398 m.postConcat(*srcMatrix);
1399 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001400 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001401
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001402 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1403 if (NULL == sqVB) {
1404 GrPrintf("Failed to create static rect vb.\n");
1405 return;
1406 }
1407 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001408 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1409#else
1410
1411 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001412#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001413 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001414#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001415 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1416#endif
1417
tomhudson@google.com93813632011-10-27 20:21:16 +00001418 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1419 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001420 srcRects[0] = &srcRect;
1421 srcMatrices[0] = srcMatrix;
1422
1423 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1424#endif
1425}
1426
1427void GrContext::drawVertices(const GrPaint& paint,
1428 GrPrimitiveType primitiveType,
1429 int vertexCount,
1430 const GrPoint positions[],
1431 const GrPoint texCoords[],
1432 const GrColor colors[],
1433 const uint16_t indices[],
1434 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001435 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001436
1437 GrDrawTarget::AutoReleaseGeometry geo;
1438
1439 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1440
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001441 bool hasTexCoords[GrPaint::kTotalStages] = {
1442 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1443 0 // remaining stages use positions
1444 };
1445
1446 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001447
1448 if (NULL != colors) {
1449 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001450 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001451 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001452
1453 if (sizeof(GrPoint) != vertexSize) {
1454 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001455 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001456 return;
1457 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001458 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001459 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001460 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1461 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001462 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001463 NULL,
1464 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001465 void* curVertex = geo.vertices();
1466
1467 for (int i = 0; i < vertexCount; ++i) {
1468 *((GrPoint*)curVertex) = positions[i];
1469
1470 if (texOffsets[0] > 0) {
1471 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1472 }
1473 if (colorOffset > 0) {
1474 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1475 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001476 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001477 }
1478 } else {
1479 target->setVertexSourceToArray(layout, positions, vertexCount);
1480 }
1481
bsalomon@google.com91958362011-06-13 17:58:13 +00001482 // we don't currently apply offscreen AA to this path. Need improved
1483 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001484
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001485 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001486 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001487 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001488 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001489 target->drawNonIndexed(primitiveType, 0, vertexCount);
1490 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001491}
1492
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001493///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001494
reed@google.com07f3ee12011-05-16 17:21:57 +00001495void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1496 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001497
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001498 if (path.isEmpty()) {
1499#if GR_DEBUG
1500 GrPrintf("Empty path should have been caught by canvas.\n");
1501#endif
1502 if (GrIsFillInverted(fill)) {
1503 this->drawPaint(paint);
1504 }
1505 return;
1506 }
1507
bsalomon@google.com27847de2011-02-22 20:59:41 +00001508 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001509
bsalomon@google.com289533a2011-10-27 12:34:25 +00001510 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1511
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001512 // An Assumption here is that path renderer would use some form of tweaking
1513 // the src color (either the input alpha or in the frag shader) to implement
1514 // aa. If we have some future driver-mojo path AA that can do the right
1515 // thing WRT to the blend then we'll need some query on the PR.
1516 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001517#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001518 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001519#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001520 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001521 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001522
1523 bool doOSAA = false;
1524 GrPathRenderer* pr = NULL;
1525 if (prAA) {
1526 pr = this->getPathRenderer(path, fill, true);
1527 if (NULL == pr) {
1528 prAA = false;
1529 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill);
1530 pr = this->getPathRenderer(path, fill, false);
1531 }
1532 } else {
1533 pr = this->getPathRenderer(path, fill, false);
1534 }
1535
bsalomon@google.com30085192011-08-19 15:42:31 +00001536 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001537#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001538 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001539#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001540 return;
1541 }
1542
bsalomon@google.com289533a2011-10-27 12:34:25 +00001543 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate);
bsalomon@google.comee435122011-07-01 14:57:55 +00001544 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001545
bsalomon@google.com289533a2011-10-27 12:34:25 +00001546 if (doOSAA) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001547 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001548
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001549 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001550 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1551 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001552 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001553 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001554 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001555 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001556 return;
1557 }
1558 }
reed@google.com70c136e2011-06-03 19:51:26 +00001559
reed@google.com07f3ee12011-05-16 17:21:57 +00001560 GrRect pathBounds = path.getBounds();
1561 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001562 if (NULL != translate) {
1563 pathBounds.offset(*translate);
1564 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001565 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001566 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001567 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001568 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001569 return;
1570 }
1571 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001572 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001573 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1574 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001575 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1576 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1577 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001578 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001579 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1580 }
1581 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001582 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001583 if (GrIsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001584 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1585 GrRect rect;
1586 if (clipIBounds.fTop < bound.fTop) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001587 rect.iset(clipIBounds.fLeft, clipIBounds.fTop,
1588 clipIBounds.fRight, bound.fTop);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001589 target->drawSimpleRect(rect, NULL, stageMask);
1590 }
1591 if (clipIBounds.fLeft < bound.fLeft) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001592 rect.iset(clipIBounds.fLeft, bound.fTop,
1593 bound.fLeft, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001594 target->drawSimpleRect(rect, NULL, stageMask);
1595 }
1596 if (clipIBounds.fRight > bound.fRight) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001597 rect.iset(bound.fRight, bound.fTop,
1598 clipIBounds.fRight, bound.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001599 target->drawSimpleRect(rect, NULL, stageMask);
1600 }
1601 if (clipIBounds.fBottom > bound.fBottom) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +00001602 rect.iset(clipIBounds.fLeft, bound.fBottom,
1603 clipIBounds.fRight, clipIBounds.fBottom);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001604 target->drawSimpleRect(rect, NULL, stageMask);
1605 }
1606 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001607 return;
1608 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001609 }
1610 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001611}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001612
bsalomon@google.com27847de2011-02-22 20:59:41 +00001613////////////////////////////////////////////////////////////////////////////////
1614
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001615bool GrContext::supportsShaders() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +00001616 return fGpu->getCaps().fShaderSupport;
bsalomon@google.com1f221a72011-08-23 20:54:07 +00001617}
1618
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001619void GrContext::flush(int flagsBitfield) {
1620 if (kDiscard_FlushBit & flagsBitfield) {
1621 fDrawBuffer->reset();
1622 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001623 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001624 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001625 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001626 fGpu->forceRenderTargetFlush();
1627 }
1628}
1629
1630void GrContext::flushText() {
1631 if (kText_DrawCategory == fLastDrawCategory) {
1632 flushDrawBuffer();
1633 }
1634}
1635
1636void GrContext::flushDrawBuffer() {
1637#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001638 if (fDrawBuffer) {
1639 fDrawBuffer->playback(fGpu);
1640 fDrawBuffer->reset();
1641 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001642#endif
1643}
1644
bsalomon@google.com6f379512011-11-16 20:36:03 +00001645void GrContext::internalWriteTexturePixels(GrTexture* texture,
1646 int left, int top,
1647 int width, int height,
1648 GrPixelConfig config,
1649 const void* buffer,
1650 size_t rowBytes,
1651 uint32_t flags) {
1652 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001653 ASSERT_OWNED_RESOURCE(texture);
1654
bsalomon@google.com6f379512011-11-16 20:36:03 +00001655 if (!(kDontFlush_PixelOpsFlag & flags)) {
1656 this->flush();
1657 }
1658 // TODO: use scratch texture to perform conversion
1659 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1660 GrPixelConfigIsUnpremultiplied(config)) {
1661 return;
1662 }
1663
1664 fGpu->writeTexturePixels(texture, left, top, width, height,
1665 config, buffer, rowBytes);
1666}
1667
1668bool GrContext::internalReadTexturePixels(GrTexture* texture,
1669 int left, int top,
1670 int width, int height,
1671 GrPixelConfig config,
1672 void* buffer,
1673 size_t rowBytes,
1674 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001675 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001676 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001677
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001678 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001679 GrRenderTarget* target = texture->asRenderTarget();
1680 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001681 return this->internalReadRenderTargetPixels(target,
1682 left, top, width, height,
1683 config, buffer, rowBytes,
1684 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001685 } else {
1686 return false;
1687 }
1688}
1689
bsalomon@google.com6f379512011-11-16 20:36:03 +00001690bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1691 int left, int top,
1692 int width, int height,
1693 GrPixelConfig config,
1694 void* buffer,
1695 size_t rowBytes,
1696 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001697 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001698 ASSERT_OWNED_RESOURCE(target);
1699
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001700 if (NULL == target) {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001701 target = fGpu->getRenderTarget();
1702 if (NULL == target) {
1703 return false;
1704 }
1705 }
1706
1707 // PM <-> UPM conversion requires a draw. Currently we only support drawing
1708 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not
1709 // not supported at this time.
1710 if (GrPixelConfigIsUnpremultiplied(target->config()) &&
1711 !GrPixelConfigIsUnpremultiplied(config)) {
1712 return false;
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001713 }
1714
bsalomon@google.com6f379512011-11-16 20:36:03 +00001715 if (!(kDontFlush_PixelOpsFlag & flags)) {
1716 this->flush();
1717 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001718
1719 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001720 bool swapRAndB = NULL != src &&
1721 fGpu->preferredReadPixelsConfig(config) ==
1722 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001723
1724 bool flipY = NULL != src &&
1725 fGpu->readPixelsWillPayForYFlip(target, left, top,
1726 width, height, config,
1727 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001728 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1729 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001730
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001731 if (NULL == src && alphaConversion) {
1732 // we should fallback to cpu conversion here. This could happen when
1733 // we were given an external render target by the client that is not
1734 // also a texture (e.g. FBO 0 in GL)
1735 return false;
1736 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001737 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001738 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001739 if (flipY || swapRAndB || alphaConversion) {
1740 GrAssert(NULL != src);
1741 if (swapRAndB) {
1742 config = GrPixelConfigSwapRAndB(config);
1743 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001744 }
1745 // Make the scratch a render target because we don't have a robust
1746 // readTexturePixels as of yet (it calls this function).
1747 const GrTextureDesc desc = {
1748 kRenderTarget_GrTextureFlagBit,
1749 kNone_GrAALevel,
1750 width, height,
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001751 { config }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001752 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001753
1754 ast.set(this, desc);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001755 GrTexture* texture = ast.texture();
1756 if (!texture) {
1757 return false;
1758 }
1759 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001760 GrAssert(NULL != target);
1761
1762 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001763 reset_target_state(fGpu);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001764
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001765 fGpu->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001766
1767 GrSamplerState sampler;
1768 sampler.setClampNoFilter();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001769 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001770 GrMatrix matrix;
1771 if (flipY) {
1772 matrix.setTranslate(SK_Scalar1 * left,
1773 SK_Scalar1 * (top + height));
1774 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1775 } else {
1776 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1777 }
1778 matrix.postIDiv(src->width(), src->height());
1779 sampler.setMatrix(matrix);
1780 fGpu->setSamplerState(0, sampler);
1781 fGpu->setTexture(0, src);
1782 GrRect rect;
1783 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1784 fGpu->drawSimpleRect(rect, NULL, 0x1);
1785 left = 0;
1786 top = 0;
1787 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001788 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001789 left, top, width, height,
1790 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001791}
1792
bsalomon@google.com6f379512011-11-16 20:36:03 +00001793void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1794 int left, int top,
1795 int width, int height,
1796 GrPixelConfig config,
1797 const void* buffer,
1798 size_t rowBytes,
1799 uint32_t flags) {
1800 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001801 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001802
1803 if (NULL == target) {
1804 target = fGpu->getRenderTarget();
1805 if (NULL == target) {
1806 return;
1807 }
1808 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001809
1810 // TODO: when underlying api has a direct way to do this we should use it
1811 // (e.g. glDrawPixels on desktop GL).
1812
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001813 // If the RT is also a texture and we don't have to do PM/UPM conversion
1814 // then take the texture path, which we expect to be at least as fast or
1815 // faster since it doesn't use an intermediate texture as we do below.
1816
1817#if !GR_MAC_BUILD
1818 // At least some drivers on the Mac get confused when glTexImage2D is called
1819 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1820 // determine what OS versions and/or HW is affected.
1821 if (NULL != target->asTexture() &&
1822 GrPixelConfigIsUnpremultiplied(target->config()) ==
1823 GrPixelConfigIsUnpremultiplied(config)) {
1824
1825 this->internalWriteTexturePixels(target->asTexture(),
1826 left, top, width, height,
1827 config, buffer, rowBytes, flags);
1828 return;
1829 }
1830#endif
1831
1832 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1833 GrPixelConfigSwapRAndB(config);
1834 if (swapRAndB) {
1835 config = GrPixelConfigSwapRAndB(config);
1836 }
1837
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001838 const GrTextureDesc desc = {
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001839 kNone_GrTextureFlags, kNone_GrAALevel, width, height, { config }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001840 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001841 GrAutoScratchTexture ast(this, desc);
1842 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001843 if (NULL == texture) {
1844 return;
1845 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001846 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1847 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001848
bsalomon@google.com27847de2011-02-22 20:59:41 +00001849 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com82c7bd82011-11-09 15:32:29 +00001850 reset_target_state(fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001851
1852 GrMatrix matrix;
1853 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1854 fGpu->setViewMatrix(matrix);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001855 fGpu->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001856 fGpu->setTexture(0, texture);
1857
1858 GrSamplerState sampler;
1859 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001860 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001861 sampler.setMatrix(matrix);
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001862 sampler.setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001863 fGpu->setSamplerState(0, sampler);
1864
1865 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1866 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001867 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001868 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1869 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001870 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001871 return;
1872 }
1873 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1874 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1875}
1876////////////////////////////////////////////////////////////////////////////////
1877
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001878void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001879
1880 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1881 int s = i + GrPaint::kFirstTextureStage;
1882 target->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001883 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001884 target->setSamplerState(s, *paint.getTextureSampler(i));
1885 }
1886
1887 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1888
1889 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1890 int s = i + GrPaint::kFirstMaskStage;
1891 target->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001892 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001893 target->setSamplerState(s, *paint.getMaskSampler(i));
1894 }
1895
bsalomon@google.com27847de2011-02-22 20:59:41 +00001896 target->setColor(paint.fColor);
1897
1898 if (paint.fDither) {
1899 target->enableState(GrDrawTarget::kDither_StateBit);
1900 } else {
1901 target->disableState(GrDrawTarget::kDither_StateBit);
1902 }
1903 if (paint.fAntiAlias) {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001904 target->enableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001905 } else {
bsalomon@google.com289533a2011-10-27 12:34:25 +00001906 target->disableState(GrDrawTarget::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001907 }
1908 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001909 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001910
1911 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1912 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1913 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001914}
1915
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001916GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001917 DrawCategory category) {
1918 if (category != fLastDrawCategory) {
1919 flushDrawBuffer();
1920 fLastDrawCategory = category;
1921 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001922 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001923 GrDrawTarget* target = fGpu;
1924 switch (category) {
1925 case kText_DrawCategory:
1926#if DEFER_TEXT_RENDERING
1927 target = fDrawBuffer;
1928 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1929#else
1930 target = fGpu;
1931#endif
1932 break;
1933 case kUnbuffered_DrawCategory:
1934 target = fGpu;
1935 break;
1936 case kBuffered_DrawCategory:
1937 target = fDrawBuffer;
1938 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1939 break;
1940 }
1941 return target;
1942}
1943
bsalomon@google.com289533a2011-10-27 12:34:25 +00001944GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1945 GrPathFill fill,
1946 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001947 if (NULL == fPathRendererChain) {
1948 fPathRendererChain =
1949 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1950 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001951 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path,
1952 fill, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001953}
1954
bsalomon@google.com27847de2011-02-22 20:59:41 +00001955////////////////////////////////////////////////////////////////////////////////
1956
bsalomon@google.com27847de2011-02-22 20:59:41 +00001957void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001958 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001959 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001960 fGpu->setRenderTarget(target);
1961}
1962
1963GrRenderTarget* GrContext::getRenderTarget() {
1964 return fGpu->getRenderTarget();
1965}
1966
1967const GrRenderTarget* GrContext::getRenderTarget() const {
1968 return fGpu->getRenderTarget();
1969}
1970
1971const GrMatrix& GrContext::getMatrix() const {
1972 return fGpu->getViewMatrix();
1973}
1974
1975void GrContext::setMatrix(const GrMatrix& m) {
1976 fGpu->setViewMatrix(m);
1977}
1978
1979void GrContext::concatMatrix(const GrMatrix& m) const {
1980 fGpu->preConcatViewMatrix(m);
1981}
1982
1983static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1984 intptr_t mask = 1 << shift;
1985 if (pred) {
1986 bits |= mask;
1987 } else {
1988 bits &= ~mask;
1989 }
1990 return bits;
1991}
1992
1993void GrContext::resetStats() {
1994 fGpu->resetStats();
1995}
1996
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001997const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001998 return fGpu->getStats();
1999}
2000
2001void GrContext::printStats() const {
2002 fGpu->printStats();
2003}
2004
bsalomon@google.com583a1e32011-08-17 13:42:46 +00002005GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00002006 fGpu = gpu;
2007 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00002008 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002009
bsalomon@google.com30085192011-08-19 15:42:31 +00002010 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002011
bsalomon@google.com50398bf2011-07-26 20:45:30 +00002012 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
2013 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002014 fFontCache = new GrFontCache(fGpu);
2015
2016 fLastDrawCategory = kUnbuffered_DrawCategory;
2017
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002018 fDrawBuffer = NULL;
2019 fDrawBufferVBAllocPool = NULL;
2020 fDrawBufferIBAllocPool = NULL;
2021
bsalomon@google.com205d4602011-04-25 12:43:45 +00002022 fAAFillRectIndexBuffer = NULL;
2023 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00002024
bsalomon@google.com18c9c192011-09-22 21:01:31 +00002025 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize;
2026 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) {
bsalomon@google.com91958362011-06-13 17:58:13 +00002027 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
2028 }
2029 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00002030
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002031 this->setupDrawBuffer();
2032}
2033
2034void GrContext::setupDrawBuffer() {
2035
2036 GrAssert(NULL == fDrawBuffer);
2037 GrAssert(NULL == fDrawBufferVBAllocPool);
2038 GrAssert(NULL == fDrawBufferIBAllocPool);
2039
bsalomon@google.com27847de2011-02-22 20:59:41 +00002040#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002041 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002042 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002043 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
2044 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002045 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00002046 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00002047 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002048 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
2049
bsalomon@google.com471d4712011-08-23 15:45:25 +00002050 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
2051 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00002052 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002053#endif
2054
2055#if BATCH_RECT_TO_RECT
2056 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
2057#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00002058}
2059
bsalomon@google.com27847de2011-02-22 20:59:41 +00002060GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
2061 GrDrawTarget* target;
2062#if DEFER_TEXT_RENDERING
2063 target = prepareToDraw(paint, kText_DrawCategory);
2064#else
2065 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
2066#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002067 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002068 return target;
2069}
2070
2071const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2072 return fGpu->getQuadIndexBuffer();
2073}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002074
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002075void GrContext::convolveInX(GrTexture* texture,
2076 const SkRect& rect,
2077 const float* kernel,
2078 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002079 ASSERT_OWNED_RESOURCE(texture);
2080
bsalomon@google.com99621082011-11-15 16:47:16 +00002081 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002082 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2083}
2084
2085void GrContext::convolveInY(GrTexture* texture,
2086 const SkRect& rect,
2087 const float* kernel,
2088 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002089 ASSERT_OWNED_RESOURCE(texture);
2090
bsalomon@google.com99621082011-11-15 16:47:16 +00002091 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002092 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
2093}
2094
2095void GrContext::convolve(GrTexture* texture,
2096 const SkRect& rect,
2097 float imageIncrement[2],
2098 const float* kernel,
2099 int kernelWidth) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002100 ASSERT_OWNED_RESOURCE(texture);
2101
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002102 GrDrawTarget::AutoStateRestore asr(fGpu);
2103 GrMatrix sampleM;
2104 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
2105 GrSamplerState::kClamp_WrapMode,
2106 GrSamplerState::kConvolution_Filter);
2107 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002108 sampleM.setIDiv(texture->width(), texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002109 sampler.setMatrix(sampleM);
2110 fGpu->setSamplerState(0, sampler);
2111 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002112 fGpu->setTexture(0, texture);
senorblanco@chromium.org60014ca2011-11-09 16:05:58 +00002113 fGpu->setColor(0xFFFFFFFF);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00002114 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002115 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2116}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002117
2118///////////////////////////////////////////////////////////////////////////////