blob: 2a12399555801869f3375d7ebf9341797e8325db [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
bsalomon@google.com1fadb202011-12-12 16:10:08 +000010#include "GrContext.h"
11
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
13#include "GrClipIterator.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000014#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000015#include "GrIndexBuffer.h"
16#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000017#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000018#include "GrPathUtils.h"
bsalomon@google.com50398bf2011-07-26 20:45:30 +000019#include "GrResourceCache.h"
bsalomon@google.com558a75b2011-08-08 17:01:14 +000020#include "GrStencilBuffer.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000021#include "GrTextStrike.h"
bsalomon@google.com8c2fe992011-09-13 15:27:18 +000022#include "SkTLazy.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000023#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024
25#define DEFER_TEXT_RENDERING 1
26
27#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
28
bsalomon@google.comd46e2422011-09-23 17:40:07 +000029// When we're using coverage AA but the blend is incompatible (given gpu
30// limitations) should we disable AA or draw wrong?
bsalomon@google.com950d7a82011-09-28 15:05:33 +000031#define DISABLE_COVERAGE_AA_FOR_BLEND 1
bsalomon@google.comd46e2422011-09-23 17:40:07 +000032
bsalomon@google.com8ccaddd2011-08-09 16:49:03 +000033static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
34static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
bsalomon@google.com27847de2011-02-22 20:59:41 +000035
36static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
37static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
38
39// We are currently only batching Text and drawRectToRect, both
40// of which use the quad index buffer.
41static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
42static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
43
bsalomon@google.combc4b6542011-11-19 13:56:11 +000044#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this)
45
bsalomon@google.com05ef5102011-05-02 21:14:59 +000046GrContext* GrContext::Create(GrEngine engine,
47 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000048 GrContext* ctx = NULL;
49 GrGpu* fGpu = GrGpu::Create(engine, context3D);
50 if (NULL != fGpu) {
51 ctx = new GrContext(fGpu);
52 fGpu->unref();
53 }
54 return ctx;
55}
56
bsalomon@google.com27847de2011-02-22 20:59:41 +000057GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000058 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000059 delete fTextureCache;
60 delete fFontCache;
61 delete fDrawBuffer;
62 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000063 delete fDrawBufferIBAllocPool;
bsalomon@google.com30085192011-08-19 15:42:31 +000064
bsalomon@google.com205d4602011-04-25 12:43:45 +000065 GrSafeUnref(fAAFillRectIndexBuffer);
66 GrSafeUnref(fAAStrokeRectIndexBuffer);
67 fGpu->unref();
bsalomon@google.com30085192011-08-19 15:42:31 +000068 GrSafeUnref(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +000069}
70
bsalomon@google.com8fe72472011-03-30 21:26:44 +000071void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000072 contextDestroyed();
73 this->setupDrawBuffer();
74}
75
76void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000077 // abandon first to so destructors
78 // don't try to free the resources in the API.
79 fGpu->abandonResources();
80
bsalomon@google.com30085192011-08-19 15:42:31 +000081 // a path renderer may be holding onto resources that
82 // are now unusable
83 GrSafeSetNull(fPathRendererChain);
84
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBuffer;
86 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000087
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBufferVBAllocPool;
89 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferIBAllocPool;
92 fDrawBufferIBAllocPool = NULL;
93
bsalomon@google.com205d4602011-04-25 12:43:45 +000094 GrSafeSetNull(fAAFillRectIndexBuffer);
95 GrSafeSetNull(fAAStrokeRectIndexBuffer);
96
bsalomon@google.com8fe72472011-03-30 21:26:44 +000097 fTextureCache->removeAll();
98 fFontCache->freeAll();
99 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100}
101
102void GrContext::resetContext() {
103 fGpu->markContextDirty();
104}
105
106void GrContext::freeGpuResources() {
107 this->flush();
108 fTextureCache->removeAll();
109 fFontCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000110 // a path renderer may be holding onto resources
111 GrSafeSetNull(fPathRendererChain);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000112}
113
twiz@google.com05e70242012-01-27 19:12:00 +0000114size_t GrContext::getGpuTextureCacheBytes() const {
115 return fTextureCache->getCachedResourceBytes();
116}
117
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000118////////////////////////////////////////////////////////////////////////////////
119
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000120int GrContext::PaintStageVertexLayoutBits(
121 const GrPaint& paint,
122 const bool hasTexCoords[GrPaint::kTotalStages]) {
123 int stageMask = paint.getActiveStageMask();
124 int layout = 0;
125 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
126 if ((1 << i) & stageMask) {
127 if (NULL != hasTexCoords && hasTexCoords[i]) {
128 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
129 } else {
130 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
131 }
132 }
133 }
134 return layout;
135}
136
137
138////////////////////////////////////////////////////////////////////////////////
139
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000140enum {
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000141 // flags for textures
142 kNPOTBit = 0x1,
143 kFilterBit = 0x2,
144 kScratchBit = 0x4,
145
146 // resource type
147 kTextureBit = 0x8,
148 kStencilBufferBit = 0x10
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000149};
150
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000151GrTexture* GrContext::TextureCacheEntry::texture() const {
152 if (NULL == fEntry) {
153 return NULL;
154 } else {
155 return (GrTexture*) fEntry->resource();
156 }
157}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000158
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000159namespace {
160// returns true if this is a "special" texture because of gpu NPOT limitations
161bool gen_texture_key_values(const GrGpu* gpu,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000162 const GrSamplerState* sampler,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000163 GrContext::TextureKey clientKey,
164 int width,
165 int height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000166 int sampleCnt,
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000167 bool scratch,
168 uint32_t v[4]) {
169 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t));
170 // we assume we only need 16 bits of width and height
171 // assert that texture creation will fail anyway if this assumption
172 // would cause key collisions.
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000173 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000174 v[0] = clientKey & 0xffffffffUL;
175 v[1] = (clientKey >> 32) & 0xffffffffUL;
176 v[2] = width | (height << 16);
177
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000178 v[3] = (sampleCnt << 24);
179 GrAssert(sampleCnt >= 0 && sampleCnt < 256);
180
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000181 if (!gpu->getCaps().fNPOTTextureTileSupport) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000182 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
183
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000184 bool tiled = NULL != sampler &&
185 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
186 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000187
188 if (tiled && !isPow2) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000189 v[3] |= kNPOTBit;
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000190 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000191 v[3] |= kFilterBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000192 }
193 }
194 }
195
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000196 if (scratch) {
197 v[3] |= kScratchBit;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000198 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000199
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000200 v[3] |= kTextureBit;
201
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000202 return v[3] & kNPOTBit;
203}
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000204
205// we should never have more than one stencil buffer with same combo of
206// (width,height,samplecount)
207void gen_stencil_key_values(int width, int height,
208 int sampleCnt, uint32_t v[4]) {
209 v[0] = width;
210 v[1] = height;
211 v[2] = sampleCnt;
212 v[3] = kStencilBufferBit;
213}
214
215void gen_stencil_key_values(const GrStencilBuffer* sb,
216 uint32_t v[4]) {
217 gen_stencil_key_values(sb->width(), sb->height(),
218 sb->numSamples(), v);
219}
bsalomon@google.com82c7bd82011-11-09 15:32:29 +0000220
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000221}
222
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000223GrContext::TextureCacheEntry GrContext::findAndLockTexture(
224 TextureKey key,
225 int width,
226 int height,
227 const GrSamplerState* sampler) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000228 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000229 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000230 GrResourceKey resourceKey(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000231 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
232 GrResourceCache::kNested_LockType));
233}
234
bsalomon@google.comfb309512011-11-30 14:13:48 +0000235bool GrContext::isTextureInCache(TextureKey key,
236 int width,
237 int height,
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000238 const GrSamplerState* sampler) const {
bsalomon@google.comfb309512011-11-30 14:13:48 +0000239 uint32_t v[4];
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000240 gen_texture_key_values(fGpu, sampler, key, width, height, 0, false, v);
bsalomon@google.comfb309512011-11-30 14:13:48 +0000241 GrResourceKey resourceKey(v);
242 return fTextureCache->hasKey(resourceKey);
243}
244
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000245GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000246 ASSERT_OWNED_RESOURCE(sb);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000247 uint32_t v[4];
248 gen_stencil_key_values(sb, v);
249 GrResourceKey resourceKey(v);
250 return fTextureCache->createAndLock(resourceKey, sb);
251}
252
253GrStencilBuffer* GrContext::findStencilBuffer(int width, int height,
254 int sampleCnt) {
255 uint32_t v[4];
256 gen_stencil_key_values(width, height, sampleCnt, v);
257 GrResourceKey resourceKey(v);
258 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey,
259 GrResourceCache::kSingle_LockType);
260 if (NULL != entry) {
261 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource();
262 return sb;
263 } else {
264 return NULL;
265 }
266}
267
268void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000269 ASSERT_OWNED_RESOURCE(sbEntry->resource());
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000270 fTextureCache->unlock(sbEntry);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000271}
272
273static void stretchImage(void* dst,
274 int dstW,
275 int dstH,
276 void* src,
277 int srcW,
278 int srcH,
279 int bpp) {
280 GrFixed dx = (srcW << 16) / dstW;
281 GrFixed dy = (srcH << 16) / dstH;
282
283 GrFixed y = dy >> 1;
284
285 int dstXLimit = dstW*bpp;
286 for (int j = 0; j < dstH; ++j) {
287 GrFixed x = dx >> 1;
288 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
289 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
290 for (int i = 0; i < dstXLimit; i += bpp) {
291 memcpy((uint8_t*) dstRow + i,
292 (uint8_t*) srcRow + (x>>16)*bpp,
293 bpp);
294 x += dx;
295 }
296 y += dy;
297 }
298}
299
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000300GrContext::TextureCacheEntry GrContext::createAndLockTexture(
301 TextureKey key,
302 const GrSamplerState* sampler,
303 const GrTextureDesc& desc,
304 void* srcData,
305 size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000306 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000307
308#if GR_DUMP_TEXTURE_UPLOAD
309 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
310#endif
311
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000312 TextureCacheEntry entry;
313 uint32_t v[4];
314 bool special = gen_texture_key_values(fGpu, sampler, key,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000315 desc.fWidth, desc.fHeight,
316 desc.fSampleCnt, false, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000317 GrResourceKey resourceKey(v);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000318
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000319 if (special) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000320 GrAssert(NULL != sampler);
321 TextureCacheEntry clampEntry = this->findAndLockTexture(key,
322 desc.fWidth,
323 desc.fHeight,
324 NULL);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000325
326 if (NULL == clampEntry.texture()) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000327 clampEntry = this->createAndLockTexture(key, NULL, desc,
328 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.com8f9cbd62011-12-09 15:55:34 +0000345 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +0000346 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000347 drawState->setRenderTarget(texture->asRenderTarget());
348 drawState->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.
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000354 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000355 filter = GrSamplerState::kNearest_Filter;
356 } else {
357 filter = GrSamplerState::kBilinear_Filter;
358 }
bsalomon@google.com1e266f82011-12-12 16:11:33 +0000359 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
360 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000361
362 static const GrVertexLayout layout =
363 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
364 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
365
366 if (arg.succeeded()) {
367 GrPoint* verts = (GrPoint*) arg.vertices();
368 verts[0].setIRectFan(0, 0,
369 texture->width(),
370 texture->height(),
371 2*sizeof(GrPoint));
372 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
373 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
374 0, 4);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000375 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000376 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000377 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000378 } else {
379 // TODO: Our CPU stretch doesn't filter. But we create separate
380 // stretched textures when the sampler state is either filtered or
381 // not. Either implement filtered stretch blit on CPU or just create
382 // one when FBO case fails.
383
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000384 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000385 // no longer need to clamp at min RT size.
386 rtDesc.fWidth = GrNextPow2(desc.fWidth);
387 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000388 int bpp = GrBytesPerPixel(desc.fConfig);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000389 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000390 rtDesc.fWidth *
391 rtDesc.fHeight);
392 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
393 srcData, desc.fWidth, desc.fHeight, bpp);
394
395 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
396
397 GrTexture* texture = fGpu->createTexture(rtDesc,
398 stretchedPixels.get(),
399 stretchedRowBytes);
400 GrAssert(NULL != texture);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000401 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000402 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000403 fTextureCache->unlock(clampEntry.cacheEntry());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000404
405 } else {
406 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
407 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000408 entry.set(fTextureCache->createAndLock(resourceKey, texture));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000409 }
410 }
411 return entry;
412}
413
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000414namespace {
415inline void gen_scratch_tex_key_values(const GrGpu* gpu,
416 const GrTextureDesc& desc,
417 uint32_t v[4]) {
418 // Instead of a client-provided key of the texture contents
419 // we create a key of from the descriptor.
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000420 GrContext::TextureKey descKey = (desc.fFlags << 8) |
bsalomon@google.com64c4fe42011-11-05 14:51:01 +0000421 ((uint64_t) desc.fConfig << 32);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000422 // this code path isn't friendly to tiling with NPOT restricitons
423 // We just pass ClampNoFilter()
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000424 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +0000425 desc.fHeight, desc.fSampleCnt, true, v);
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000426}
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000427}
428
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000429GrContext::TextureCacheEntry GrContext::lockScratchTexture(
430 const GrTextureDesc& inDesc,
431 ScratchTexMatch match) {
432
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000433 GrTextureDesc desc = inDesc;
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000434 if (kExact_ScratchTexMatch != match) {
435 // bin by pow2 with a reasonable min
436 static const int MIN_SIZE = 256;
437 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
438 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
439 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000440
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000441 GrResourceEntry* entry;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000442 int origWidth = desc.fWidth;
443 int origHeight = desc.fHeight;
444 bool doubledW = false;
445 bool doubledH = false;
446
447 do {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000448 uint32_t v[4];
449 gen_scratch_tex_key_values(fGpu, desc, v);
450 GrResourceKey key(v);
bsalomon@google.com558a75b2011-08-08 17:01:14 +0000451 entry = fTextureCache->findAndLock(key,
452 GrResourceCache::kNested_LockType);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000453 // if we miss, relax the fit of the flags...
454 // then try doubling width... then height.
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000455 if (NULL != entry || kExact_ScratchTexMatch == match) {
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000456 break;
457 }
458 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
459 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
460 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
461 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
462 } else if (!doubledW) {
463 desc.fFlags = inDesc.fFlags;
464 desc.fWidth *= 2;
465 doubledW = true;
466 } else if (!doubledH) {
467 desc.fFlags = inDesc.fFlags;
468 desc.fWidth = origWidth;
469 desc.fHeight *= 2;
470 doubledH = true;
471 } else {
472 break;
473 }
474
475 } while (true);
476
477 if (NULL == entry) {
478 desc.fFlags = inDesc.fFlags;
479 desc.fWidth = origWidth;
480 desc.fHeight = origHeight;
481 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
482 if (NULL != texture) {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000483 uint32_t v[4];
484 gen_scratch_tex_key_values(fGpu, desc, v);
485 GrResourceKey key(v);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000486 entry = fTextureCache->createAndLock(key, texture);
487 }
488 }
489
490 // If the caller gives us the same desc/sampler twice we don't want
491 // to return the same texture the second time (unless it was previously
492 // released). So we detach the entry from the cache and reattach at release.
493 if (NULL != entry) {
494 fTextureCache->detach(entry);
495 }
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000496 return TextureCacheEntry(entry);
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000497}
498
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000499void GrContext::unlockTexture(TextureCacheEntry entry) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +0000500 ASSERT_OWNED_RESOURCE(entry.texture());
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000501 // If this is a scratch texture we detached it from the cache
502 // while it was locked (to avoid two callers simultaneously getting
503 // the same texture).
504 if (kScratchBit & entry.cacheEntry()->key().getValue32(3)) {
505 fTextureCache->reattachAndUnlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000506 } else {
bsalomon@google.com50398bf2011-07-26 20:45:30 +0000507 fTextureCache->unlock(entry.cacheEntry());
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000508 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000509}
510
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000511GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000512 void* srcData,
513 size_t rowBytes) {
514 return fGpu->createTexture(desc, srcData, rowBytes);
515}
516
517void GrContext::getTextureCacheLimits(int* maxTextures,
518 size_t* maxTextureBytes) const {
519 fTextureCache->getLimits(maxTextures, maxTextureBytes);
520}
521
522void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
523 fTextureCache->setLimits(maxTextures, maxTextureBytes);
524}
525
bsalomon@google.com91958362011-06-13 17:58:13 +0000526int GrContext::getMaxTextureSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000527 return fGpu->getCaps().fMaxTextureSize;
bsalomon@google.com91958362011-06-13 17:58:13 +0000528}
529
530int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000531 return fGpu->getCaps().fMaxRenderTargetSize;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000532}
533
534///////////////////////////////////////////////////////////////////////////////
535
bsalomon@google.come269f212011-11-07 13:29:52 +0000536GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) {
537 return fGpu->createPlatformTexture(desc);
538}
539
540GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) {
541 return fGpu->createPlatformRenderTarget(desc);
542}
543
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000544///////////////////////////////////////////////////////////////////////////////
545
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000546bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
bsalomon@google.com1f221a72011-08-23 20:54:07 +0000547 int width, int height) const {
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000548 const GrDrawTarget::Caps& caps = fGpu->getCaps();
549 if (!caps.f8BitPaletteSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000550 return false;
551 }
552
bsalomon@google.com27847de2011-02-22 20:59:41 +0000553 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
554
555 if (!isPow2) {
bsalomon@google.com1fadb202011-12-12 16:10:08 +0000556 bool tiled = NULL != sampler &&
557 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
558 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
bsalomon@google.com18c9c192011-09-22 21:01:31 +0000559 if (tiled && !caps.fNPOTTextureTileSupport) {
bsalomon@google.com27847de2011-02-22 20:59:41 +0000560 return false;
561 }
562 }
563 return true;
564}
565
566////////////////////////////////////////////////////////////////////////////////
567
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000568const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
569
bsalomon@google.com27847de2011-02-22 20:59:41 +0000570void GrContext::setClip(const GrClip& clip) {
571 fGpu->setClip(clip);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000572 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000573}
574
575void GrContext::setClip(const GrIRect& rect) {
576 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000577 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000578 fGpu->setClip(clip);
579}
580
581////////////////////////////////////////////////////////////////////////////////
582
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000583void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000584 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000585 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000586}
587
588void GrContext::drawPaint(const GrPaint& paint) {
589 // set rect to be big enough to fill the space, but not super-huge, so we
590 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000591 GrRect r;
592 r.setLTRB(0, 0,
593 GrIntToScalar(getRenderTarget()->width()),
594 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000595 GrMatrix inverse;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000596 SkTLazy<GrPaint> tmpPaint;
597 const GrPaint* p = &paint;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000598 GrDrawState* drawState = fGpu->drawState();
599 GrAutoMatrix am;
600
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000601 // We attempt to map r by the inverse matrix and draw that. mapRect will
602 // map the four corners and bound them with a new rect. This will not
603 // produce a correct result for some perspective matrices.
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000604 if (!this->getMatrix().hasPerspective()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000605 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000606 GrPrintf("Could not invert matrix");
607 return;
608 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000609 inverse.mapRect(&r);
610 } else {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000611 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000612 if (!drawState->getViewInverse(&inverse)) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000613 GrPrintf("Could not invert matrix");
614 return;
615 }
616 tmpPaint.set(paint);
617 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse);
618 p = tmpPaint.get();
619 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000620 am.set(this, GrMatrix::I());
bsalomon@google.com27847de2011-02-22 20:59:41 +0000621 }
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000622 // by definition this fills the entire clip, no need for AA
623 if (paint.fAntiAlias) {
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000624 if (!tmpPaint.isValid()) {
625 tmpPaint.set(paint);
626 p = tmpPaint.get();
627 }
628 GrAssert(p == tmpPaint.get());
629 tmpPaint.get()->fAntiAlias = false;
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000630 }
631 this->drawRect(*p, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000632}
633
bsalomon@google.com205d4602011-04-25 12:43:45 +0000634////////////////////////////////////////////////////////////////////////////////
635
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000636namespace {
637inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
638 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
639}
640}
641
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000642////////////////////////////////////////////////////////////////////////////////
643
bsalomon@google.com27847de2011-02-22 20:59:41 +0000644/* create a triangle strip that strokes the specified triangle. There are 8
645 unique vertices, but we repreat the last 2 to close up. Alternatively we
646 could use an indices array, and then only send 8 verts, but not sure that
647 would be faster.
648 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000649static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000650 GrScalar width) {
651 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000652 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000653
654 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
655 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
656 verts[2].set(rect.fRight - rad, rect.fTop + rad);
657 verts[3].set(rect.fRight + rad, rect.fTop - rad);
658 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
659 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
660 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
661 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
662 verts[8] = verts[0];
663 verts[9] = verts[1];
664}
665
bsalomon@google.com205d4602011-04-25 12:43:45 +0000666static void setInsetFan(GrPoint* pts, size_t stride,
667 const GrRect& r, GrScalar dx, GrScalar dy) {
668 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
669}
670
671static const uint16_t gFillAARectIdx[] = {
672 0, 1, 5, 5, 4, 0,
673 1, 2, 6, 6, 5, 1,
674 2, 3, 7, 7, 6, 2,
675 3, 0, 4, 4, 7, 3,
676 4, 5, 6, 6, 7, 4,
677};
678
679int GrContext::aaFillRectIndexCount() const {
680 return GR_ARRAY_COUNT(gFillAARectIdx);
681}
682
683GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
684 if (NULL == fAAFillRectIndexBuffer) {
685 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
686 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000687 if (NULL != fAAFillRectIndexBuffer) {
688 #if GR_DEBUG
689 bool updated =
690 #endif
691 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
692 sizeof(gFillAARectIdx));
693 GR_DEBUGASSERT(updated);
694 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000695 }
696 return fAAFillRectIndexBuffer;
697}
698
699static const uint16_t gStrokeAARectIdx[] = {
700 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
701 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
702 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
703 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
704
705 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
706 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
707 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
708 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
709
710 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
711 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
712 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
713 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
714};
715
716int GrContext::aaStrokeRectIndexCount() const {
717 return GR_ARRAY_COUNT(gStrokeAARectIdx);
718}
719
720GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
721 if (NULL == fAAStrokeRectIndexBuffer) {
722 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
723 false);
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000724 if (NULL != fAAStrokeRectIndexBuffer) {
725 #if GR_DEBUG
726 bool updated =
727 #endif
728 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
729 sizeof(gStrokeAARectIdx));
730 GR_DEBUGASSERT(updated);
731 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000732 }
733 return fAAStrokeRectIndexBuffer;
734}
735
bsalomon@google.coma3108262011-10-10 14:08:47 +0000736static GrVertexLayout aa_rect_layout(const GrDrawTarget* target,
737 bool useCoverage) {
738 GrVertexLayout layout = 0;
tomhudson@google.com93813632011-10-27 20:21:16 +0000739 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000740 if (NULL != target->getDrawState().getTexture(s)) {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000741 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
742 }
743 }
744 if (useCoverage) {
745 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
746 } else {
747 layout |= GrDrawTarget::kColor_VertexLayoutBit;
748 }
749 return layout;
750}
751
bsalomon@google.com205d4602011-04-25 12:43:45 +0000752void GrContext::fillAARect(GrDrawTarget* target,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000753 const GrRect& devRect,
754 bool useVertexCoverage) {
755 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000756
757 size_t vsize = GrDrawTarget::VertexSize(layout);
758
759 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000760 if (!geo.succeeded()) {
761 GrPrintf("Failed to get space for vertices!\n");
762 return;
763 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000764 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer();
765 if (NULL == indexBuffer) {
766 GrPrintf("Failed to create index buffer!\n");
767 return;
768 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000769
770 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
771
772 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
773 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
774
775 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
776 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
777
778 verts += sizeof(GrPoint);
779 for (int i = 0; i < 4; ++i) {
780 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
781 }
782
bsalomon@google.coma3108262011-10-10 14:08:47 +0000783 GrColor innerColor;
784 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000785 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000786 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000787 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000788 }
789
bsalomon@google.com205d4602011-04-25 12:43:45 +0000790 verts += 4 * vsize;
791 for (int i = 0; i < 4; ++i) {
792 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
793 }
794
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000795 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000796
797 target->drawIndexed(kTriangles_PrimitiveType, 0,
798 0, 8, this->aaFillRectIndexCount());
799}
800
bsalomon@google.coma3108262011-10-10 14:08:47 +0000801void GrContext::strokeAARect(GrDrawTarget* target,
802 const GrRect& devRect,
803 const GrVec& devStrokeSize,
804 bool useVertexCoverage) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000805 const GrScalar& dx = devStrokeSize.fX;
806 const GrScalar& dy = devStrokeSize.fY;
807 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
808 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
809
bsalomon@google.com205d4602011-04-25 12:43:45 +0000810 GrScalar spare;
811 {
812 GrScalar w = devRect.width() - dx;
813 GrScalar h = devRect.height() - dy;
814 spare = GrMin(w, h);
815 }
816
817 if (spare <= 0) {
818 GrRect r(devRect);
819 r.inset(-rx, -ry);
bsalomon@google.coma3108262011-10-10 14:08:47 +0000820 fillAARect(target, r, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000821 return;
822 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000823 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000824 size_t vsize = GrDrawTarget::VertexSize(layout);
825
826 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000827 if (!geo.succeeded()) {
828 GrPrintf("Failed to get space for vertices!\n");
829 return;
830 }
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000831 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer();
832 if (NULL == indexBuffer) {
833 GrPrintf("Failed to create index buffer!\n");
834 return;
835 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000836
837 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
838
839 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
840 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
841 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
842 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
843
844 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
845 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
846 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
847 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
848
849 verts += sizeof(GrPoint);
850 for (int i = 0; i < 4; ++i) {
851 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
852 }
853
bsalomon@google.coma3108262011-10-10 14:08:47 +0000854 GrColor innerColor;
855 if (useVertexCoverage) {
bsalomon@google.come10f6fd2011-10-11 20:15:26 +0000856 innerColor = 0xffffffff;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000857 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000858 innerColor = target->getDrawState().getColor();
bsalomon@google.coma3108262011-10-10 14:08:47 +0000859 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000860 verts += 4 * vsize;
861 for (int i = 0; i < 8; ++i) {
862 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
863 }
864
865 verts += 8 * vsize;
866 for (int i = 0; i < 8; ++i) {
867 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
868 }
869
bsalomon@google.com9b09c9e2011-08-31 13:33:40 +0000870 target->setIndexSourceToBuffer(indexBuffer);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000871 target->drawIndexed(kTriangles_PrimitiveType,
872 0, 0, 16, aaStrokeRectIndexCount());
873}
874
reed@google.com20efde72011-05-09 17:00:02 +0000875/**
876 * Returns true if the rects edges are integer-aligned.
877 */
878static bool isIRect(const GrRect& r) {
879 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
880 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
881}
882
bsalomon@google.com205d4602011-04-25 12:43:45 +0000883static bool apply_aa_to_rect(GrDrawTarget* target,
bsalomon@google.com205d4602011-04-25 12:43:45 +0000884 const GrRect& rect,
885 GrScalar width,
886 const GrMatrix* matrix,
887 GrMatrix* combinedMatrix,
bsalomon@google.coma3108262011-10-10 14:08:47 +0000888 GrRect* devRect,
889 bool* useVertexCoverage) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000890 // we use a simple coverage ramp to do aa on axis-aligned rects
891 // we check if the rect will be axis-aligned, and the rect won't land on
892 // integer coords.
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000893
bsalomon@google.coma3108262011-10-10 14:08:47 +0000894 // we are keeping around the "tweak the alpha" trick because
895 // it is our only hope for the fixed-pipe implementation.
896 // In a shader implementation we can give a separate coverage input
bsalomon@google.com289533a2011-10-27 12:34:25 +0000897 // TODO: remove this ugliness when we drop the fixed-pipe impl
bsalomon@google.coma3108262011-10-10 14:08:47 +0000898 *useVertexCoverage = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000899 if (!target->canTweakAlphaForCoverage()) {
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000900 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +0000901#if GR_DEBUG
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000902 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +0000903#endif
bsalomon@google.coma3108262011-10-10 14:08:47 +0000904 return false;
bsalomon@google.com2eba7952012-01-12 13:47:37 +0000905 } else {
906 *useVertexCoverage = true;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000907 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000908 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000909 const GrDrawState& drawState = target->getDrawState();
910 if (drawState.getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000911 return false;
912 }
913
bsalomon@google.com471d4712011-08-23 15:45:25 +0000914 if (0 == width && target->willUseHWAALines()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000915 return false;
916 }
917
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000918 if (!drawState.getViewMatrix().preservesAxisAlignment()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000919 return false;
920 }
921
922 if (NULL != matrix &&
923 !matrix->preservesAxisAlignment()) {
924 return false;
925 }
926
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000927 *combinedMatrix = drawState.getViewMatrix();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000928 if (NULL != matrix) {
929 combinedMatrix->preConcat(*matrix);
930 GrAssert(combinedMatrix->preservesAxisAlignment());
931 }
932
933 combinedMatrix->mapRect(devRect, rect);
934 devRect->sort();
935
936 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +0000937 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000938 } else {
939 return true;
940 }
941}
942
bsalomon@google.com27847de2011-02-22 20:59:41 +0000943void GrContext::drawRect(const GrPaint& paint,
944 const GrRect& rect,
945 GrScalar width,
946 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000947 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000948
949 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000950 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000951
bsalomon@google.com205d4602011-04-25 12:43:45 +0000952 GrRect devRect = rect;
953 GrMatrix combinedMatrix;
bsalomon@google.coma3108262011-10-10 14:08:47 +0000954 bool useVertexCoverage;
bsalomon@google.com289533a2011-10-27 12:34:25 +0000955 bool needAA = paint.fAntiAlias &&
956 !this->getRenderTarget()->isMultisampled();
957 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
958 &combinedMatrix, &devRect,
959 &useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000960
961 if (doAA) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000962 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000963 if (width >= 0) {
964 GrVec strokeSize;;
965 if (width > 0) {
966 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +0000967 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000968 strokeSize.setAbs(strokeSize);
969 } else {
970 strokeSize.set(GR_Scalar1, GR_Scalar1);
971 }
bsalomon@google.coma3108262011-10-10 14:08:47 +0000972 strokeAARect(target, devRect, strokeSize, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000973 } else {
bsalomon@google.coma3108262011-10-10 14:08:47 +0000974 fillAARect(target, devRect, useVertexCoverage);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000975 }
976 return;
977 }
978
bsalomon@google.com27847de2011-02-22 20:59:41 +0000979 if (width >= 0) {
980 // TODO: consider making static vertex buffers for these cases.
981 // Hairline could be done by just adding closing vertex to
982 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000983 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
984
bsalomon@google.com27847de2011-02-22 20:59:41 +0000985 static const int worstCaseVertCount = 10;
986 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
987
988 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +0000989 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000990 return;
991 }
992
993 GrPrimitiveType primType;
994 int vertCount;
995 GrPoint* vertex = geo.positions();
996
997 if (width > 0) {
998 vertCount = 10;
999 primType = kTriangleStrip_PrimitiveType;
1000 setStrokeRectStrip(vertex, rect, width);
1001 } else {
1002 // hairline
1003 vertCount = 5;
1004 primType = kLineStrip_PrimitiveType;
1005 vertex[0].set(rect.fLeft, rect.fTop);
1006 vertex[1].set(rect.fRight, rect.fTop);
1007 vertex[2].set(rect.fRight, rect.fBottom);
1008 vertex[3].set(rect.fLeft, rect.fBottom);
1009 vertex[4].set(rect.fLeft, rect.fTop);
1010 }
1011
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001012 GrDrawState::AutoViewMatrixRestore avmr;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001013 if (NULL != matrix) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001014 GrDrawState* drawState = target->drawState();
1015 avmr.set(drawState);
1016 drawState->preConcatViewMatrix(*matrix);
1017 drawState->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001018 }
1019
1020 target->drawNonIndexed(primType, 0, vertCount);
1021 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001022#if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001023 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001024 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1025 if (NULL == sqVB) {
1026 GrPrintf("Failed to create static rect vb.\n");
1027 return;
1028 }
1029 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001030 GrDrawState* drawState = target->drawState();
1031 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001032 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001033 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001034 0, rect.height(), rect.fTop,
1035 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001036
1037 if (NULL != matrix) {
1038 m.postConcat(*matrix);
1039 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001040 drawState->preConcatViewMatrix(m);
1041 drawState->preConcatSamplerMatrices(stageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001042
bsalomon@google.com27847de2011-02-22 20:59:41 +00001043 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001044#else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001045 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001046#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001047 }
1048}
1049
1050void GrContext::drawRectToRect(const GrPaint& paint,
1051 const GrRect& dstRect,
1052 const GrRect& srcRect,
1053 const GrMatrix* dstMatrix,
1054 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001055 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001056
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001057 // srcRect refers to paint's first texture
1058 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001059 drawRect(paint, dstRect, -1, dstMatrix);
1060 return;
1061 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001062
bsalomon@google.com27847de2011-02-22 20:59:41 +00001063 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1064
1065#if GR_STATIC_RECT_VB
1066 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001067 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001068 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001069 GrDrawState::AutoViewMatrixRestore avmr(drawState);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001070
1071 GrMatrix m;
1072
1073 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1074 0, dstRect.height(), dstRect.fTop,
1075 0, 0, GrMatrix::I()[8]);
1076 if (NULL != dstMatrix) {
1077 m.postConcat(*dstMatrix);
1078 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001079 drawState->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001080
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001081 // srcRect refers to first stage
1082 int otherStageMask = paint.getActiveStageMask() &
1083 (~(1 << GrPaint::kFirstTextureStage));
1084 if (otherStageMask) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001085 drawState->preConcatSamplerMatrices(otherStageMask, m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001086 }
1087
bsalomon@google.com27847de2011-02-22 20:59:41 +00001088 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1089 0, srcRect.height(), srcRect.fTop,
1090 0, 0, GrMatrix::I()[8]);
1091 if (NULL != srcMatrix) {
1092 m.postConcat(*srcMatrix);
1093 }
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001094 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001095
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001096 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
1097 if (NULL == sqVB) {
1098 GrPrintf("Failed to create static rect vb.\n");
1099 return;
1100 }
1101 target->setVertexSourceToBuffer(layout, sqVB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001102 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1103#else
1104
1105 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001106#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001107 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001108#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001109 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1110#endif
1111
tomhudson@google.com93813632011-10-27 20:21:16 +00001112 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1113 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL};
bsalomon@google.com27847de2011-02-22 20:59:41 +00001114 srcRects[0] = &srcRect;
1115 srcMatrices[0] = srcMatrix;
1116
1117 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1118#endif
1119}
1120
1121void GrContext::drawVertices(const GrPaint& paint,
1122 GrPrimitiveType primitiveType,
1123 int vertexCount,
1124 const GrPoint positions[],
1125 const GrPoint texCoords[],
1126 const GrColor colors[],
1127 const uint16_t indices[],
1128 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001129 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130
1131 GrDrawTarget::AutoReleaseGeometry geo;
1132
1133 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1134
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001135 bool hasTexCoords[GrPaint::kTotalStages] = {
1136 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1137 0 // remaining stages use positions
1138 };
1139
1140 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001141
1142 if (NULL != colors) {
1143 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001144 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001145 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146
1147 if (sizeof(GrPoint) != vertexSize) {
1148 if (!geo.set(target, layout, vertexCount, 0)) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001149 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001150 return;
1151 }
tomhudson@google.com93813632011-10-27 20:21:16 +00001152 int texOffsets[GrDrawState::kMaxTexCoords];
bsalomon@google.com27847de2011-02-22 20:59:41 +00001153 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001154 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1155 texOffsets,
bsalomon@google.comaeb21602011-08-30 18:13:44 +00001156 &colorOffset,
bsalomon@google.coma3108262011-10-10 14:08:47 +00001157 NULL,
1158 NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159 void* curVertex = geo.vertices();
1160
1161 for (int i = 0; i < vertexCount; ++i) {
1162 *((GrPoint*)curVertex) = positions[i];
1163
1164 if (texOffsets[0] > 0) {
1165 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1166 }
1167 if (colorOffset > 0) {
1168 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1169 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001170 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001171 }
1172 } else {
1173 target->setVertexSourceToArray(layout, positions, vertexCount);
1174 }
1175
bsalomon@google.com91958362011-06-13 17:58:13 +00001176 // we don't currently apply offscreen AA to this path. Need improved
1177 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001178
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001179 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001180 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001181 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001182 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001183 target->drawNonIndexed(primitiveType, 0, vertexCount);
1184 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001185}
1186
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001187///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com150d2842012-01-12 20:19:56 +00001188#include "SkDraw.h"
1189#include "SkRasterClip.h"
1190
1191namespace {
1192
1193SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
1194 switch (fill) {
1195 case kWinding_PathFill:
1196 return SkPath::kWinding_FillType;
1197 case kEvenOdd_PathFill:
1198 return SkPath::kEvenOdd_FillType;
1199 case kInverseWinding_PathFill:
1200 return SkPath::kInverseWinding_FillType;
1201 case kInverseEvenOdd_PathFill:
1202 return SkPath::kInverseEvenOdd_FillType;
1203 default:
1204 GrCrash("Unexpected fill.");
1205 return SkPath::kWinding_FillType;
1206 }
1207}
1208
1209// gets device coord bounds of path (not considering the fill) and clip. The
1210// path bounds will be a subset of the clip bounds. returns false if path bounds
1211// would be empty.
1212bool get_path_and_clip_bounds(const GrDrawTarget* target,
1213 const GrPath& path,
1214 const GrVec* translate,
1215 GrIRect* pathBounds,
1216 GrIRect* clipBounds) {
1217 // compute bounds as intersection of rt size, clip, and path
1218 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
1219 if (NULL == rt) {
1220 return false;
1221 }
1222 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
1223 const GrClip& clip = target->getClip();
1224 if (clip.hasConservativeBounds()) {
1225 clip.getConservativeBounds().roundOut(clipBounds);
1226 if (!pathBounds->intersect(*clipBounds)) {
1227 return false;
1228 }
1229 } else {
1230 // pathBounds is currently the rt extent, set clip bounds to that rect.
1231 *clipBounds = *pathBounds;
1232 }
1233 GrRect pathSBounds = path.getBounds();
1234 if (!pathSBounds.isEmpty()) {
1235 if (NULL != translate) {
1236 pathSBounds.offset(*translate);
1237 }
1238 target->getDrawState().getViewMatrix().mapRect(&pathSBounds,
1239 pathSBounds);
1240 GrIRect pathIBounds;
1241 pathSBounds.roundOut(&pathIBounds);
1242 if (!pathBounds->intersect(pathIBounds)) {
1243 return false;
1244 }
1245 } else {
1246 return false;
1247 }
1248 return true;
1249}
1250
1251/**
1252 * sw rasterizes path to A8 mask using the context's matrix and uploads to a
1253 * scratch texture.
1254 */
1255
1256bool sw_draw_path_to_mask_texture(const GrPath& clientPath,
1257 const GrIRect& pathDevBounds,
1258 GrPathFill fill,
1259 GrContext* context,
1260 const GrPoint* translate,
1261 GrAutoScratchTexture* tex) {
1262 SkPaint paint;
1263 SkPath tmpPath;
1264 const SkPath* pathToDraw = &clientPath;
1265 if (kHairLine_PathFill == fill) {
1266 paint.setStyle(SkPaint::kStroke_Style);
1267 paint.setStrokeWidth(SK_Scalar1);
1268 } else {
1269 paint.setStyle(SkPaint::kFill_Style);
1270 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
1271 if (skfill != pathToDraw->getFillType()) {
1272 tmpPath = *pathToDraw;
1273 tmpPath.setFillType(skfill);
1274 pathToDraw = &tmpPath;
1275 }
1276 }
1277 paint.setAntiAlias(true);
1278 paint.setColor(SK_ColorWHITE);
1279
1280 GrMatrix matrix = context->getMatrix();
1281 if (NULL != translate) {
1282 matrix.postTranslate(translate->fX, translate->fY);
1283 }
1284
1285 matrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
1286 -pathDevBounds.fTop * SK_Scalar1);
1287 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
1288 pathDevBounds.height());
1289
1290 SkBitmap bm;
1291 bm.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
1292 if (!bm.allocPixels()) {
1293 return false;
1294 }
1295 sk_bzero(bm.getPixels(), bm.getSafeSize());
1296
1297 SkDraw draw;
1298 sk_bzero(&draw, sizeof(draw));
1299 SkRasterClip rc(bounds);
1300 draw.fRC = &rc;
1301 draw.fClip = &rc.bwRgn();
1302 draw.fMatrix = &matrix;
1303 draw.fBitmap = &bm;
1304 draw.drawPath(*pathToDraw, paint);
1305
1306 const GrTextureDesc desc = {
1307 kNone_GrTextureFlags,
bsalomon@google.com150d2842012-01-12 20:19:56 +00001308 bounds.fRight,
1309 bounds.fBottom,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001310 kAlpha_8_GrPixelConfig,
1311 {0} // samples
bsalomon@google.com150d2842012-01-12 20:19:56 +00001312 };
1313
1314 tex->set(context, desc);
1315 GrTexture* texture = tex->texture();
1316
1317 if (NULL == texture) {
1318 return false;
1319 }
1320 SkAutoLockPixels alp(bm);
1321 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
1322 bm.getPixels(), bm.rowBytes());
1323 return true;
1324}
1325
1326void draw_around_inv_path(GrDrawTarget* target,
1327 GrDrawState::StageMask stageMask,
1328 const GrIRect& clipBounds,
1329 const GrIRect& pathBounds) {
1330 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1331 GrRect rect;
1332 if (clipBounds.fTop < pathBounds.fTop) {
1333 rect.iset(clipBounds.fLeft, clipBounds.fTop,
1334 clipBounds.fRight, pathBounds.fTop);
1335 target->drawSimpleRect(rect, NULL, stageMask);
1336 }
1337 if (clipBounds.fLeft < pathBounds.fLeft) {
1338 rect.iset(clipBounds.fLeft, pathBounds.fTop,
1339 pathBounds.fLeft, pathBounds.fBottom);
1340 target->drawSimpleRect(rect, NULL, stageMask);
1341 }
1342 if (clipBounds.fRight > pathBounds.fRight) {
1343 rect.iset(pathBounds.fRight, pathBounds.fTop,
1344 clipBounds.fRight, pathBounds.fBottom);
1345 target->drawSimpleRect(rect, NULL, stageMask);
1346 }
1347 if (clipBounds.fBottom > pathBounds.fBottom) {
1348 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
1349 clipBounds.fRight, clipBounds.fBottom);
1350 target->drawSimpleRect(rect, NULL, stageMask);
1351 }
1352}
1353
1354}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001355
reed@google.com07f3ee12011-05-16 17:21:57 +00001356void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1357 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001358
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001359 if (path.isEmpty()) {
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001360 if (GrIsFillInverted(fill)) {
1361 this->drawPaint(paint);
1362 }
1363 return;
1364 }
1365
bsalomon@google.com27847de2011-02-22 20:59:41 +00001366 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001367 GrDrawState::StageMask stageMask = paint.getActiveStageMask();
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001368
bsalomon@google.com289533a2011-10-27 12:34:25 +00001369 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
1370
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001371 // An Assumption here is that path renderer would use some form of tweaking
1372 // the src color (either the input alpha or in the frag shader) to implement
1373 // aa. If we have some future driver-mojo path AA that can do the right
1374 // thing WRT to the blend then we'll need some query on the PR.
1375 if (disable_coverage_aa_for_blend(target)) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001376#if GR_DEBUG
bsalomon@google.com979432b2011-11-05 21:38:22 +00001377 //GrPrintf("Turning off AA to correctly apply blend.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001378#endif
bsalomon@google.com289533a2011-10-27 12:34:25 +00001379 prAA = false;
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001380 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001381
bsalomon@google.com289533a2011-10-27 12:34:25 +00001382 GrPathRenderer* pr = NULL;
1383 if (prAA) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001384 pr = this->getPathRenderer(path, fill, target, true);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001385 if (NULL == pr) {
bsalomon@google.com150d2842012-01-12 20:19:56 +00001386 GrAutoScratchTexture ast;
1387 GrIRect pathBounds, clipBounds;
1388 if (!get_path_and_clip_bounds(target, path, translate,
1389 &pathBounds, &clipBounds)) {
1390 return;
1391 }
bsalomon@google.com150d2842012-01-12 20:19:56 +00001392 if (NULL == pr && sw_draw_path_to_mask_texture(path, pathBounds,
1393 fill, this,
1394 translate, &ast)) {
1395 GrTexture* texture = ast.texture();
1396 GrAssert(NULL != texture);
1397 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1398 enum {
1399 kPathMaskStage = GrPaint::kTotalStages,
1400 };
1401 target->drawState()->setTexture(kPathMaskStage, texture);
1402 target->drawState()->sampler(kPathMaskStage)->reset();
1403 GrScalar w = GrIntToScalar(pathBounds.width());
1404 GrScalar h = GrIntToScalar(pathBounds.height());
1405 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
1406 h / texture->height());
1407 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
1408 srcRects[kPathMaskStage] = &maskRect;
1409 stageMask |= 1 << kPathMaskStage;
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001410 GrRect dstRect = GrRect::MakeLTRB(
1411 SK_Scalar1* pathBounds.fLeft,
1412 SK_Scalar1* pathBounds.fTop,
1413 SK_Scalar1* pathBounds.fRight,
1414 SK_Scalar1* pathBounds.fBottom);
bsalomon@google.com150d2842012-01-12 20:19:56 +00001415 target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
1416 target->drawState()->setTexture(kPathMaskStage, NULL);
1417 if (GrIsFillInverted(fill)) {
1418 draw_around_inv_path(target, stageMask,
1419 clipBounds, pathBounds);
1420 }
1421 return;
1422 }
bsalomon@google.com289533a2011-10-27 12:34:25 +00001423 }
1424 } else {
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001425 pr = this->getPathRenderer(path, fill, target, false);
bsalomon@google.com289533a2011-10-27 12:34:25 +00001426 }
1427
bsalomon@google.com30085192011-08-19 15:42:31 +00001428 if (NULL == pr) {
bsalomon@google.com1983f392011-10-10 15:17:58 +00001429#if GR_DEBUG
bsalomon@google.com30085192011-08-19 15:42:31 +00001430 GrPrintf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001431#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001432 return;
1433 }
1434
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001435 pr->drawPath(path, fill, translate, target, stageMask, prAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001436}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001437
bsalomon@google.com27847de2011-02-22 20:59:41 +00001438////////////////////////////////////////////////////////////////////////////////
1439
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001440void GrContext::flush(int flagsBitfield) {
1441 if (kDiscard_FlushBit & flagsBitfield) {
1442 fDrawBuffer->reset();
1443 } else {
bsalomon@google.comc4364992011-11-07 15:54:49 +00001444 this->flushDrawBuffer();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001445 }
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001446 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001447 fGpu->forceRenderTargetFlush();
1448 }
1449}
1450
1451void GrContext::flushText() {
1452 if (kText_DrawCategory == fLastDrawCategory) {
1453 flushDrawBuffer();
1454 }
1455}
1456
1457void GrContext::flushDrawBuffer() {
1458#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001459 if (fDrawBuffer) {
1460 fDrawBuffer->playback(fGpu);
1461 fDrawBuffer->reset();
1462 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463#endif
1464}
1465
bsalomon@google.com6f379512011-11-16 20:36:03 +00001466void GrContext::internalWriteTexturePixels(GrTexture* texture,
1467 int left, int top,
1468 int width, int height,
1469 GrPixelConfig config,
1470 const void* buffer,
1471 size_t rowBytes,
1472 uint32_t flags) {
1473 SK_TRACE_EVENT0("GrContext::writeTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001474 ASSERT_OWNED_RESOURCE(texture);
1475
bsalomon@google.com6f379512011-11-16 20:36:03 +00001476 if (!(kDontFlush_PixelOpsFlag & flags)) {
1477 this->flush();
1478 }
1479 // TODO: use scratch texture to perform conversion
1480 if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
1481 GrPixelConfigIsUnpremultiplied(config)) {
1482 return;
1483 }
1484
1485 fGpu->writeTexturePixels(texture, left, top, width, height,
1486 config, buffer, rowBytes);
1487}
1488
1489bool GrContext::internalReadTexturePixels(GrTexture* texture,
1490 int left, int top,
1491 int width, int height,
1492 GrPixelConfig config,
1493 void* buffer,
1494 size_t rowBytes,
1495 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001496 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001497 ASSERT_OWNED_RESOURCE(texture);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001498
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001499 // TODO: code read pixels for textures that aren't also rendertargets
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001500 GrRenderTarget* target = texture->asRenderTarget();
1501 if (NULL != target) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001502 return this->internalReadRenderTargetPixels(target,
1503 left, top, width, height,
1504 config, buffer, rowBytes,
1505 flags);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001506 } else {
1507 return false;
1508 }
1509}
1510
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001511#include "SkConfig8888.h"
1512
1513namespace {
1514/**
1515 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel
1516 * formats are representable as Config8888 and so the function returns false
1517 * if the GrPixelConfig has no equivalent Config8888.
1518 */
1519bool grconfig_to_config8888(GrPixelConfig config,
1520 SkCanvas::Config8888* config8888) {
1521 switch (config) {
1522 case kRGBA_8888_PM_GrPixelConfig:
1523 *config8888 = SkCanvas::kRGBA_Premul_Config8888;
1524 return true;
1525 case kRGBA_8888_UPM_GrPixelConfig:
1526 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888;
1527 return true;
1528 case kBGRA_8888_PM_GrPixelConfig:
1529 *config8888 = SkCanvas::kBGRA_Premul_Config8888;
1530 return true;
1531 case kBGRA_8888_UPM_GrPixelConfig:
1532 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888;
1533 return true;
1534 default:
1535 return false;
1536 }
1537}
1538}
1539
bsalomon@google.com6f379512011-11-16 20:36:03 +00001540bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
1541 int left, int top,
1542 int width, int height,
1543 GrPixelConfig config,
1544 void* buffer,
1545 size_t rowBytes,
1546 uint32_t flags) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001547 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001548 ASSERT_OWNED_RESOURCE(target);
1549
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001550 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001551 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001552 if (NULL == target) {
1553 return false;
1554 }
1555 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001556
bsalomon@google.com6f379512011-11-16 20:36:03 +00001557 if (!(kDontFlush_PixelOpsFlag & flags)) {
1558 this->flush();
1559 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001560
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001561 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1562 GrPixelConfigIsUnpremultiplied(config) &&
1563 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1564 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1565 if (!grconfig_to_config8888(target->config(), &srcConfig8888) ||
1566 !grconfig_to_config8888(config, &dstConfig8888)) {
1567 return false;
1568 }
1569 // do read back using target's own config
1570 this->internalReadRenderTargetPixels(target,
1571 left, top,
1572 width, height,
1573 target->config(),
1574 buffer, rowBytes,
1575 kDontFlush_PixelOpsFlag);
1576 // sw convert the pixels to unpremul config
1577 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer);
1578 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888,
1579 pixels, rowBytes, srcConfig8888,
1580 width, height);
1581 return true;
1582 }
1583
bsalomon@google.comc4364992011-11-07 15:54:49 +00001584 GrTexture* src = target->asTexture();
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001585 bool swapRAndB = NULL != src &&
1586 fGpu->preferredReadPixelsConfig(config) ==
1587 GrPixelConfigSwapRAndB(config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001588
1589 bool flipY = NULL != src &&
1590 fGpu->readPixelsWillPayForYFlip(target, left, top,
1591 width, height, config,
1592 rowBytes);
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001593 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1594 GrPixelConfigIsUnpremultiplied(config));
bsalomon@google.comc4364992011-11-07 15:54:49 +00001595
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001596 if (NULL == src && alphaConversion) {
1597 // we should fallback to cpu conversion here. This could happen when
1598 // we were given an external render target by the client that is not
1599 // also a texture (e.g. FBO 0 in GL)
1600 return false;
1601 }
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001602 // we draw to a scratch texture if any of these conversion are applied
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001603 GrAutoScratchTexture ast;
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001604 if (flipY || swapRAndB || alphaConversion) {
1605 GrAssert(NULL != src);
1606 if (swapRAndB) {
1607 config = GrPixelConfigSwapRAndB(config);
1608 GrAssert(kUnknown_GrPixelConfig != config);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001609 }
1610 // Make the scratch a render target because we don't have a robust
1611 // readTexturePixels as of yet (it calls this function).
1612 const GrTextureDesc desc = {
1613 kRenderTarget_GrTextureFlagBit,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001614 width, height,
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001615 config,
1616 {0}, // samples
bsalomon@google.comc4364992011-11-07 15:54:49 +00001617 };
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001618
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001619 // When a full readback is faster than a partial we could always make
1620 // the scratch exactly match the passed rect. However, if we see many
1621 // different size rectangles we will trash our texture cache and pay the
1622 // cost of creating and destroying many textures. So, we only request
1623 // an exact match when the caller is reading an entire RT.
1624 ScratchTexMatch match = kApprox_ScratchTexMatch;
1625 if (0 == left &&
1626 0 == top &&
1627 target->width() == width &&
1628 target->height() == height &&
1629 fGpu->fullReadPixelsIsFasterThanPartial()) {
1630 match = kExact_ScratchTexMatch;
1631 }
1632 ast.set(this, desc, match);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001633 GrTexture* texture = ast.texture();
1634 if (!texture) {
1635 return false;
1636 }
1637 target = texture->asRenderTarget();
bsalomon@google.comc4364992011-11-07 15:54:49 +00001638 GrAssert(NULL != target);
1639
1640 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001641 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001642 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001643 drawState->setRenderTarget(target);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001644
bsalomon@google.comc4364992011-11-07 15:54:49 +00001645 GrMatrix matrix;
1646 if (flipY) {
1647 matrix.setTranslate(SK_Scalar1 * left,
1648 SK_Scalar1 * (top + height));
1649 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1);
1650 } else {
1651 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1652 }
1653 matrix.postIDiv(src->width(), src->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001654 drawState->sampler(0)->reset(matrix);
1655 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001656 drawState->setTexture(0, src);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001657 GrRect rect;
1658 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height);
1659 fGpu->drawSimpleRect(rect, NULL, 0x1);
1660 left = 0;
1661 top = 0;
1662 }
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001663 return fGpu->readPixels(target,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001664 left, top, width, height,
1665 config, buffer, rowBytes, flipY);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001666}
1667
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001668void GrContext::resolveRenderTarget(GrRenderTarget* target) {
1669 GrAssert(target);
1670 ASSERT_OWNED_RESOURCE(target);
1671 // In the future we may track whether there are any pending draws to this
1672 // target. We don't today so we always perform a flush. We don't promise
1673 // this to our clients, though.
1674 this->flush();
1675 fGpu->resolveRenderTarget(target);
1676}
1677
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001678void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) {
1679 if (NULL == src || NULL == dst) {
1680 return;
1681 }
1682 ASSERT_OWNED_RESOURCE(src);
1683
1684 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001685 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001686 drawState->reset();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001687 drawState->setRenderTarget(dst);
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001688 GrMatrix sampleM;
1689 sampleM.setIDiv(src->width(), src->height());
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001690 drawState->setTexture(0, src);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001691 drawState->sampler(0)->reset(sampleM);
bsalomon@google.com5db3b6c2012-01-12 20:38:57 +00001692 SkRect rect = SkRect::MakeXYWH(0, 0,
1693 SK_Scalar1 * src->width(),
1694 SK_Scalar1 * src->height());
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001695 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1696}
1697
bsalomon@google.com6f379512011-11-16 20:36:03 +00001698void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
1699 int left, int top,
1700 int width, int height,
1701 GrPixelConfig config,
1702 const void* buffer,
1703 size_t rowBytes,
1704 uint32_t flags) {
1705 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001706 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com6f379512011-11-16 20:36:03 +00001707
1708 if (NULL == target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001709 target = fGpu->drawState()->getRenderTarget();
bsalomon@google.com6f379512011-11-16 20:36:03 +00001710 if (NULL == target) {
1711 return;
1712 }
1713 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001714
1715 // TODO: when underlying api has a direct way to do this we should use it
1716 // (e.g. glDrawPixels on desktop GL).
1717
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001718 // If the RT is also a texture and we don't have to do PM/UPM conversion
1719 // then take the texture path, which we expect to be at least as fast or
1720 // faster since it doesn't use an intermediate texture as we do below.
1721
1722#if !GR_MAC_BUILD
1723 // At least some drivers on the Mac get confused when glTexImage2D is called
1724 // on a texture attached to an FBO. The FBO still sees the old image. TODO:
1725 // determine what OS versions and/or HW is affected.
1726 if (NULL != target->asTexture() &&
1727 GrPixelConfigIsUnpremultiplied(target->config()) ==
1728 GrPixelConfigIsUnpremultiplied(config)) {
1729
1730 this->internalWriteTexturePixels(target->asTexture(),
1731 left, top, width, height,
1732 config, buffer, rowBytes, flags);
1733 return;
1734 }
1735#endif
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001736 if (!GrPixelConfigIsUnpremultiplied(target->config()) &&
1737 GrPixelConfigIsUnpremultiplied(config) &&
1738 !fGpu->canPreserveReadWriteUnpremulPixels()) {
1739 SkCanvas::Config8888 srcConfig8888, dstConfig8888;
1740 if (!grconfig_to_config8888(config, &srcConfig8888) ||
1741 !grconfig_to_config8888(target->config(), &dstConfig8888)) {
1742 return;
1743 }
1744 // allocate a tmp buffer and sw convert the pixels to premul
1745 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height);
1746 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer);
1747 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888,
1748 src, rowBytes, srcConfig8888,
1749 width, height);
1750 // upload the already premul pixels
1751 this->internalWriteRenderTargetPixels(target,
1752 left, top,
1753 width, height,
1754 target->config(),
1755 tmpPixels, 4 * width, flags);
1756 return;
1757 }
bsalomon@google.coma85449d2011-11-19 02:36:05 +00001758
1759 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) ==
1760 GrPixelConfigSwapRAndB(config);
1761 if (swapRAndB) {
1762 config = GrPixelConfigSwapRAndB(config);
1763 }
1764
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001765 const GrTextureDesc desc = {
bsalomon@google.com78d6cf92012-01-30 18:09:31 +00001766 kNone_GrTextureFlags, width, height, config, {0}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001767 };
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001768 GrAutoScratchTexture ast(this, desc);
1769 GrTexture* texture = ast.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001770 if (NULL == texture) {
1771 return;
1772 }
bsalomon@google.com6f379512011-11-16 20:36:03 +00001773 this->internalWriteTexturePixels(texture, 0, 0, width, height,
1774 config, buffer, rowBytes, flags);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001775
bsalomon@google.com27847de2011-02-22 20:59:41 +00001776 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001777 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.com52a5dcb2012-01-17 16:01:37 +00001778 drawState->reset();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001779
1780 GrMatrix matrix;
1781 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001782 drawState->setViewMatrix(matrix);
1783 drawState->setRenderTarget(target);
1784 drawState->setTexture(0, texture);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001785
bsalomon@google.com5c638652011-07-18 19:31:59 +00001786 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com1e266f82011-12-12 16:11:33 +00001787 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
1788 GrSamplerState::kNearest_Filter,
1789 matrix);
1790 drawState->sampler(0)->setRAndBSwap(swapRAndB);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001791
1792 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1793 static const int VCOUNT = 4;
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001794 // TODO: Use GrGpu::drawRect here
bsalomon@google.com27847de2011-02-22 20:59:41 +00001795 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1796 if (!geo.succeeded()) {
bsalomon@google.com6513cd02011-08-05 20:12:30 +00001797 GrPrintf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001798 return;
1799 }
1800 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1801 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1802}
1803////////////////////////////////////////////////////////////////////////////////
1804
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001805void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001806 GrDrawState* drawState = target->drawState();
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001807
1808 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1809 int s = i + GrPaint::kFirstTextureStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001810 drawState->setTexture(s, paint.getTexture(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001811 ASSERT_OWNED_RESOURCE(paint.getTexture(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001812 if (paint.getTexture(i)) {
1813 *drawState->sampler(s) = paint.getTextureSampler(i);
1814 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001815 }
1816
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001817 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001818
1819 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1820 int s = i + GrPaint::kFirstMaskStage;
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001821 drawState->setTexture(s, paint.getMask(i));
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001822 ASSERT_OWNED_RESOURCE(paint.getMask(i));
bsalomon@google.comf864ec42011-12-12 21:57:03 +00001823 if (paint.getMask(i)) {
1824 *drawState->sampler(s) = paint.getMaskSampler(i);
1825 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001826 }
1827
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001828 drawState->setColor(paint.fColor);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001829
1830 if (paint.fDither) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001831 drawState->enableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001832 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001833 drawState->disableState(GrDrawState::kDither_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001834 }
1835 if (paint.fAntiAlias) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001836 drawState->enableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001837 } else {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001838 drawState->disableState(GrDrawState::kHWAntialias_StateBit);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001839 }
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001840 if (paint.fColorMatrixEnabled) {
1841 drawState->enableState(GrDrawState::kColorMatrix_StateBit);
1842 } else {
1843 drawState->disableState(GrDrawState::kColorMatrix_StateBit);
1844 }
bsalomon@google.com6b67e212011-12-09 16:10:24 +00001845 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001846 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
senorblanco@chromium.org50bdad82012-01-03 20:51:57 +00001847 drawState->setColorMatrix(paint.fColorMatrix);
bsalomon@google.comdd1be602012-01-18 20:34:00 +00001848 drawState->setCoverage(paint.fCoverage);
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001849
1850 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
1851 GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
1852 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001853}
1854
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001855GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001856 DrawCategory category) {
1857 if (category != fLastDrawCategory) {
1858 flushDrawBuffer();
1859 fLastDrawCategory = category;
1860 }
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001861 this->setPaint(paint, fGpu);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001862 GrDrawTarget* target = fGpu;
1863 switch (category) {
1864 case kText_DrawCategory:
1865#if DEFER_TEXT_RENDERING
1866 target = fDrawBuffer;
1867 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1868#else
1869 target = fGpu;
1870#endif
1871 break;
1872 case kUnbuffered_DrawCategory:
1873 target = fGpu;
1874 break;
1875 case kBuffered_DrawCategory:
1876 target = fDrawBuffer;
1877 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1878 break;
1879 }
1880 return target;
1881}
1882
bsalomon@google.com289533a2011-10-27 12:34:25 +00001883GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
1884 GrPathFill fill,
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001885 const GrDrawTarget* target,
bsalomon@google.com289533a2011-10-27 12:34:25 +00001886 bool antiAlias) {
bsalomon@google.com30085192011-08-19 15:42:31 +00001887 if (NULL == fPathRendererChain) {
1888 fPathRendererChain =
1889 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
1890 }
bsalomon@google.comc2099d22012-03-02 21:26:50 +00001891 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias);
bsalomon@google.com30085192011-08-19 15:42:31 +00001892}
1893
bsalomon@google.com27847de2011-02-22 20:59:41 +00001894////////////////////////////////////////////////////////////////////////////////
1895
bsalomon@google.com27847de2011-02-22 20:59:41 +00001896void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001897 ASSERT_OWNED_RESOURCE(target);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001898 this->flush(false);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001899 fGpu->drawState()->setRenderTarget(target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001900}
1901
1902GrRenderTarget* GrContext::getRenderTarget() {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001903 return fGpu->drawState()->getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001904}
1905
1906const GrRenderTarget* GrContext::getRenderTarget() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001907 return fGpu->getDrawState().getRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001908}
1909
1910const GrMatrix& GrContext::getMatrix() const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001911 return fGpu->getDrawState().getViewMatrix();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001912}
1913
1914void GrContext::setMatrix(const GrMatrix& m) {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001915 fGpu->drawState()->setViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001916}
1917
1918void GrContext::concatMatrix(const GrMatrix& m) const {
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00001919 fGpu->drawState()->preConcatViewMatrix(m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001920}
1921
1922static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1923 intptr_t mask = 1 << shift;
1924 if (pred) {
1925 bits |= mask;
1926 } else {
1927 bits &= ~mask;
1928 }
1929 return bits;
1930}
1931
1932void GrContext::resetStats() {
1933 fGpu->resetStats();
1934}
1935
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001936const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001937 return fGpu->getStats();
1938}
1939
1940void GrContext::printStats() const {
1941 fGpu->printStats();
1942}
1943
bsalomon@google.com583a1e32011-08-17 13:42:46 +00001944GrContext::GrContext(GrGpu* gpu) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001945 fGpu = gpu;
1946 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001947 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001948
bsalomon@google.com30085192011-08-19 15:42:31 +00001949 fPathRendererChain = NULL;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001950
bsalomon@google.com50398bf2011-07-26 20:45:30 +00001951 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
1952 MAX_TEXTURE_CACHE_BYTES);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001953 fFontCache = new GrFontCache(fGpu);
1954
1955 fLastDrawCategory = kUnbuffered_DrawCategory;
1956
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001957 fDrawBuffer = NULL;
1958 fDrawBufferVBAllocPool = NULL;
1959 fDrawBufferIBAllocPool = NULL;
1960
bsalomon@google.com205d4602011-04-25 12:43:45 +00001961 fAAFillRectIndexBuffer = NULL;
1962 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001963
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001964 this->setupDrawBuffer();
1965}
1966
1967void GrContext::setupDrawBuffer() {
1968
1969 GrAssert(NULL == fDrawBuffer);
1970 GrAssert(NULL == fDrawBufferVBAllocPool);
1971 GrAssert(NULL == fDrawBufferIBAllocPool);
1972
bsalomon@google.com27847de2011-02-22 20:59:41 +00001973#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001974 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001975 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001976 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1977 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001978 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001979 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001980 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001981 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1982
bsalomon@google.com471d4712011-08-23 15:45:25 +00001983 fDrawBuffer = new GrInOrderDrawBuffer(fGpu,
1984 fDrawBufferVBAllocPool,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001985 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001986#endif
1987
1988#if BATCH_RECT_TO_RECT
1989 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1990#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001991}
1992
bsalomon@google.com27847de2011-02-22 20:59:41 +00001993GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1994 GrDrawTarget* target;
1995#if DEFER_TEXT_RENDERING
1996 target = prepareToDraw(paint, kText_DrawCategory);
1997#else
1998 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1999#endif
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002000 this->setPaint(paint, target);
bsalomon@google.com27847de2011-02-22 20:59:41 +00002001 return target;
2002}
2003
2004const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
2005 return fGpu->getQuadIndexBuffer();
2006}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002007
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002008void GrContext::convolve(GrTexture* texture,
2009 const SkRect& rect,
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00002010 const float* kernel,
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002011 int kernelWidth,
2012 GrSamplerState::FilterDirection direction) {
bsalomon@google.combc4b6542011-11-19 13:56:11 +00002013 ASSERT_OWNED_RESOURCE(texture);
2014
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002015 GrDrawTarget::AutoStateRestore asr(fGpu);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002016 GrDrawState* drawState = fGpu->drawState();
bsalomon@google.comdd1be602012-01-18 20:34:00 +00002017 GrRenderTarget* target = drawState->getRenderTarget();
2018 drawState->reset();
2019 drawState->setRenderTarget(target);
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002020 GrMatrix sampleM;
2021 sampleM.setIDiv(texture->width(), texture->height());
2022 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2023 GrSamplerState::kConvolution_Filter,
2024 sampleM);
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002025 drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel);
2026 drawState->sampler(0)->setFilterDirection(direction);
2027 drawState->setTexture(0, texture);
2028 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2029}
bsalomon@google.com1e266f82011-12-12 16:11:33 +00002030
senorblanco@chromium.org05054f12012-03-02 21:05:45 +00002031void GrContext::applyMorphology(GrTexture* texture,
2032 const SkRect& rect,
2033 int radius,
2034 GrSamplerState::Filter filter,
2035 GrSamplerState::FilterDirection direction) {
2036 ASSERT_OWNED_RESOURCE(texture);
2037 GrAssert(filter == GrSamplerState::kErode_Filter ||
2038 filter == GrSamplerState::kDilate_Filter);
2039
2040 GrDrawTarget::AutoStateRestore asr(fGpu);
2041 GrDrawState* drawState = fGpu->drawState();
2042 GrRenderTarget* target = drawState->getRenderTarget();
2043 drawState->reset();
2044 drawState->setRenderTarget(target);
2045 GrMatrix sampleM;
2046 sampleM.setIDiv(texture->width(), texture->height());
2047 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
2048 filter,
2049 sampleM);
2050 drawState->sampler(0)->setMorphologyRadius(radius);
2051 drawState->sampler(0)->setFilterDirection(direction);
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +00002052 drawState->setTexture(0, texture);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00002053 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
2054}
bsalomon@google.comc4364992011-11-07 15:54:49 +00002055
2056///////////////////////////////////////////////////////////////////////////////