blob: b829323b2e21d614ead5bbe4c93593f21826bd02 [file] [log] [blame]
bsalomon@google.com27847de2011-02-22 20:59:41 +00001/*
bsalomon@google.com1da07462011-03-10 14:51:57 +00002 Copyright 2011 Google Inc.
bsalomon@google.com27847de2011-02-22 20:59:41 +00003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
tomhudson@google.com278cbb42011-06-30 19:37:01 +000017#include "GrBufferAllocPool.h"
18#include "GrClipIterator.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000019#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000020#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000021#include "GrIndexBuffer.h"
22#include "GrInOrderDrawBuffer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000023#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000024#include "GrPathUtils.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000025#include "GrTextureCache.h"
26#include "GrTextStrike.h"
tomhudson@google.com0c8d93a2011-07-01 17:08:26 +000027#include "SkTrace.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000028
bsalomon@google.com91958362011-06-13 17:58:13 +000029// Using MSAA seems to be slower for some yet unknown reason.
30#define PREFER_MSAA_OFFSCREEN_AA 0
31#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000032
bsalomon@google.com27847de2011-02-22 20:59:41 +000033#define DEFER_TEXT_RENDERING 1
34
35#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
36
37static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
38static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
39
40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
42
43// We are currently only batching Text and drawRectToRect, both
44// of which use the quad index buffer.
45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
47
bsalomon@google.com05ef5102011-05-02 21:14:59 +000048GrContext* GrContext::Create(GrEngine engine,
49 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000050 GrContext* ctx = NULL;
51 GrGpu* fGpu = GrGpu::Create(engine, context3D);
52 if (NULL != fGpu) {
53 ctx = new GrContext(fGpu);
54 fGpu->unref();
55 }
56 return ctx;
57}
58
59GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000060 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000061}
62
63GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000064 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000065 delete fTextureCache;
66 delete fFontCache;
67 delete fDrawBuffer;
68 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000069 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000070 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000071 GrSafeUnref(fAAFillRectIndexBuffer);
72 GrSafeUnref(fAAStrokeRectIndexBuffer);
73 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000074}
75
bsalomon@google.com8fe72472011-03-30 21:26:44 +000076void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000077 contextDestroyed();
78 this->setupDrawBuffer();
79}
80
81void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000082 // abandon first to so destructors
83 // don't try to free the resources in the API.
84 fGpu->abandonResources();
85
bsalomon@google.com8fe72472011-03-30 21:26:44 +000086 delete fDrawBuffer;
87 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000088
bsalomon@google.com8fe72472011-03-30 21:26:44 +000089 delete fDrawBufferVBAllocPool;
90 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000091
bsalomon@google.com8fe72472011-03-30 21:26:44 +000092 delete fDrawBufferIBAllocPool;
93 fDrawBufferIBAllocPool = NULL;
94
bsalomon@google.com205d4602011-04-25 12:43:45 +000095 GrSafeSetNull(fAAFillRectIndexBuffer);
96 GrSafeSetNull(fAAStrokeRectIndexBuffer);
97
bsalomon@google.com8fe72472011-03-30 21:26:44 +000098 fTextureCache->removeAll();
99 fFontCache->freeAll();
100 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000101}
102
103void GrContext::resetContext() {
104 fGpu->markContextDirty();
105}
106
107void GrContext::freeGpuResources() {
108 this->flush();
109 fTextureCache->removeAll();
110 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000111}
112
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000113////////////////////////////////////////////////////////////////////////////////
114
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000115int GrContext::PaintStageVertexLayoutBits(
116 const GrPaint& paint,
117 const bool hasTexCoords[GrPaint::kTotalStages]) {
118 int stageMask = paint.getActiveStageMask();
119 int layout = 0;
120 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
121 if ((1 << i) & stageMask) {
122 if (NULL != hasTexCoords && hasTexCoords[i]) {
123 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
124 } else {
125 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
126 }
127 }
128 }
129 return layout;
130}
131
132
133////////////////////////////////////////////////////////////////////////////////
134
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000135enum {
136 kNPOTBit = 0x1,
137 kFilterBit = 0x2,
138 kKeylessBit = 0x4,
139};
140
141bool GrContext::finalizeTextureKey(GrTextureKey* key,
142 const GrSamplerState& sampler,
143 bool keyless) const {
144 uint32_t bits = 0;
145 uint16_t width = key->width();
146 uint16_t height = key->height();
147
148 if (!fGpu->npotTextureTileSupport()) {
149 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
150
151 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
152 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
153
154 if (tiled && !isPow2) {
155 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000156 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000157 bits |= kFilterBit;
158 }
159 }
160 }
161
162 if (keyless) {
163 bits |= kKeylessBit;
164 }
165 key->finalize(bits);
166 return 0 != bits;
167}
168
bsalomon@google.com27847de2011-02-22 20:59:41 +0000169GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
170 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000171 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000172 return fTextureCache->findAndLock(*key);
173}
174
175static void stretchImage(void* dst,
176 int dstW,
177 int dstH,
178 void* src,
179 int srcW,
180 int srcH,
181 int bpp) {
182 GrFixed dx = (srcW << 16) / dstW;
183 GrFixed dy = (srcH << 16) / dstH;
184
185 GrFixed y = dy >> 1;
186
187 int dstXLimit = dstW*bpp;
188 for (int j = 0; j < dstH; ++j) {
189 GrFixed x = dx >> 1;
190 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
191 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
192 for (int i = 0; i < dstXLimit; i += bpp) {
193 memcpy((uint8_t*) dstRow + i,
194 (uint8_t*) srcRow + (x>>16)*bpp,
195 bpp);
196 x += dx;
197 }
198 y += dy;
199 }
200}
201
202GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
203 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000204 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000205 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000206 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000207 GrAssert(key->width() == desc.fWidth);
208 GrAssert(key->height() == desc.fHeight);
209
210#if GR_DUMP_TEXTURE_UPLOAD
211 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
212#endif
213
214 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000215 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000216 if (special) {
217 GrTextureEntry* clampEntry;
218 GrTextureKey clampKey(*key);
219 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
220
221 if (NULL == clampEntry) {
222 clampEntry = createAndLockTexture(&clampKey,
223 GrSamplerState::ClampNoFilter(),
224 desc, srcData, rowBytes);
225 GrAssert(NULL != clampEntry);
226 if (NULL == clampEntry) {
227 return NULL;
228 }
229 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000230 GrTextureDesc rtDesc = desc;
231 rtDesc.fFlags = rtDesc.fFlags |
232 kRenderTarget_GrTextureFlagBit |
233 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000234 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
235 fGpu->minRenderTargetWidth()));
236 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
237 fGpu->minRenderTargetHeight()));
238
239 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
240
241 if (NULL != texture) {
242 GrDrawTarget::AutoStateRestore asr(fGpu);
243 fGpu->setRenderTarget(texture->asRenderTarget());
244 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000245 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000246 fGpu->setViewMatrix(GrMatrix::I());
247 fGpu->setAlpha(0xff);
248 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
249 fGpu->disableState(GrDrawTarget::kDither_StateBit |
250 GrDrawTarget::kClip_StateBit |
251 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000252 GrSamplerState::Filter filter;
253 // if filtering is not desired then we want to ensure all
254 // texels in the resampled image are copies of texels from
255 // the original.
256 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
257 filter = GrSamplerState::kNearest_Filter;
258 } else {
259 filter = GrSamplerState::kBilinear_Filter;
260 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000261 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
262 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000263 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000264 fGpu->setSamplerState(0, stretchSampler);
265
266 static const GrVertexLayout layout =
267 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
268 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
269
270 if (arg.succeeded()) {
271 GrPoint* verts = (GrPoint*) arg.vertices();
272 verts[0].setIRectFan(0, 0,
273 texture->width(),
274 texture->height(),
275 2*sizeof(GrPoint));
276 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
277 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
278 0, 4);
279 entry = fTextureCache->createAndLock(*key, texture);
280 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000281 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000282 } else {
283 // TODO: Our CPU stretch doesn't filter. But we create separate
284 // stretched textures when the sampler state is either filtered or
285 // not. Either implement filtered stretch blit on CPU or just create
286 // one when FBO case fails.
287
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000288 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000289 // no longer need to clamp at min RT size.
290 rtDesc.fWidth = GrNextPow2(desc.fWidth);
291 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000292 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000293 SkAutoSMalloc<128*128*4> stretchedPixels(bpp *
bsalomon@google.com27847de2011-02-22 20:59:41 +0000294 rtDesc.fWidth *
295 rtDesc.fHeight);
296 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
297 srcData, desc.fWidth, desc.fHeight, bpp);
298
299 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
300
301 GrTexture* texture = fGpu->createTexture(rtDesc,
302 stretchedPixels.get(),
303 stretchedRowBytes);
304 GrAssert(NULL != texture);
305 entry = fTextureCache->createAndLock(*key, texture);
306 }
307 fTextureCache->unlock(clampEntry);
308
309 } else {
310 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
311 if (NULL != texture) {
312 entry = fTextureCache->createAndLock(*key, texture);
313 } else {
314 entry = NULL;
315 }
316 }
317 return entry;
318}
319
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000320GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000321 uint32_t p0 = desc.fFormat;
322 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
323 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000324 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
325
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000326 GrTextureEntry* entry = fTextureCache->findAndLock(key);
327 if (NULL == entry) {
328 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
329 if (NULL != texture) {
330 entry = fTextureCache->createAndLock(key, texture);
331 }
332 }
333 // If the caller gives us the same desc/sampler twice we don't want
334 // to return the same texture the second time (unless it was previously
335 // released). So we detach the entry from the cache and reattach at release.
336 if (NULL != entry) {
337 fTextureCache->detach(entry);
338 }
339 return entry;
340}
341
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000342GrTextureEntry* GrContext::findApproximateKeylessTexture(
343 const GrTextureDesc& inDesc) {
344 GrTextureDesc desc = inDesc;
345 // bin by pow2 with a reasonable min
346 static const int MIN_SIZE = 256;
347 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
348 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
349
350 uint32_t p0 = desc.fFormat;
351 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
352
353 GrTextureEntry* entry;
354 bool keepTrying = true;
355 int origWidth = desc.fWidth;
356 int origHeight = desc.fHeight;
357 bool doubledW = false;
358 bool doubledH = false;
359
360 do {
361 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
362 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
363 entry = fTextureCache->findAndLock(key);
364
365 // if we miss, relax the fit of the flags...
366 // then try doubling width... then height.
367 if (NULL != entry) {
368 break;
369 }
370 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
371 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
372 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
373 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
374 } else if (!doubledW) {
375 desc.fFlags = inDesc.fFlags;
376 desc.fWidth *= 2;
377 doubledW = true;
378 } else if (!doubledH) {
379 desc.fFlags = inDesc.fFlags;
380 desc.fWidth = origWidth;
381 desc.fHeight *= 2;
382 doubledH = true;
383 } else {
384 break;
385 }
386
387 } while (true);
388
389 if (NULL == entry) {
390 desc.fFlags = inDesc.fFlags;
391 desc.fWidth = origWidth;
392 desc.fHeight = origHeight;
393 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
394 if (NULL != texture) {
395 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
396 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(),
397 true);
398 entry = fTextureCache->createAndLock(key, texture);
399 }
400 }
401
402 // If the caller gives us the same desc/sampler twice we don't want
403 // to return the same texture the second time (unless it was previously
404 // released). So we detach the entry from the cache and reattach at release.
405 if (NULL != entry) {
406 fTextureCache->detach(entry);
407 }
408 return entry;
409}
410
bsalomon@google.com27847de2011-02-22 20:59:41 +0000411void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000412 if (kKeylessBit & entry->key().getPrivateBits()) {
413 fTextureCache->reattachAndUnlock(entry);
414 } else {
415 fTextureCache->unlock(entry);
416 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000417}
418
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000419GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000420 void* srcData,
421 size_t rowBytes) {
422 return fGpu->createTexture(desc, srcData, rowBytes);
423}
424
425void GrContext::getTextureCacheLimits(int* maxTextures,
426 size_t* maxTextureBytes) const {
427 fTextureCache->getLimits(maxTextures, maxTextureBytes);
428}
429
430void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
431 fTextureCache->setLimits(maxTextures, maxTextureBytes);
432}
433
bsalomon@google.com91958362011-06-13 17:58:13 +0000434int GrContext::getMaxTextureSize() const {
435 return fGpu->maxTextureSize();
436}
437
438int GrContext::getMaxRenderTargetSize() const {
439 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000440}
441
442///////////////////////////////////////////////////////////////////////////////
443
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000444GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
445 // validate flags here so that GrGpu subclasses don't have to check
446 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
447 0 != desc.fRenderTargetFlags) {
448 return NULL;
449 }
450 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
451 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
452 return NULL;
453 }
454 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
455 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
456 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
457 return NULL;
458 }
459 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000460}
461
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000462GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000463 return fGpu->createRenderTargetFrom3DApiState();
464}
465
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000466///////////////////////////////////////////////////////////////////////////////
467
bsalomon@google.com27847de2011-02-22 20:59:41 +0000468bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
469 int width, int height) {
470 if (!fGpu->supports8BitPalette()) {
471 return false;
472 }
473
474
475 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
476
477 if (!isPow2) {
478 if (!fGpu->npotTextureSupport()) {
479 return false;
480 }
481
482 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
483 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
484 if (tiled && !fGpu->npotTextureTileSupport()) {
485 return false;
486 }
487 }
488 return true;
489}
490
491////////////////////////////////////////////////////////////////////////////////
492
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000493const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
494
bsalomon@google.com27847de2011-02-22 20:59:41 +0000495void GrContext::setClip(const GrClip& clip) {
496 fGpu->setClip(clip);
497 fGpu->enableState(GrDrawTarget::kClip_StateBit);
498}
499
500void GrContext::setClip(const GrIRect& rect) {
501 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000502 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000503 fGpu->setClip(clip);
504}
505
506////////////////////////////////////////////////////////////////////////////////
507
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000508void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000509 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000510 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000511}
512
513void GrContext::drawPaint(const GrPaint& paint) {
514 // set rect to be big enough to fill the space, but not super-huge, so we
515 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000516 GrRect r;
517 r.setLTRB(0, 0,
518 GrIntToScalar(getRenderTarget()->width()),
519 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000520 GrMatrix inverse;
521 if (fGpu->getViewInverse(&inverse)) {
522 inverse.mapRect(&r);
523 } else {
524 GrPrintf("---- fGpu->getViewInverse failed\n");
525 }
526 this->drawRect(paint, r);
527}
528
bsalomon@google.com205d4602011-04-25 12:43:45 +0000529////////////////////////////////////////////////////////////////////////////////
530
bsalomon@google.com91958362011-06-13 17:58:13 +0000531struct GrContext::OffscreenRecord {
532 OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; }
533 ~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); }
534
535 enum Downsample {
536 k4x4TwoPass_Downsample,
537 k4x4SinglePass_Downsample,
538 kFSAA_Downsample
539 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000540 int fTileSizeX;
541 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000542 int fTileCountX;
543 int fTileCountY;
544 int fScale;
545 GrTextureEntry* fEntry0;
546 GrTextureEntry* fEntry1;
547 GrDrawTarget::SavedDrawState fSavedState;
tomhudson@google.com237a4612011-07-19 15:44:00 +0000548 GrClip fClip;
bsalomon@google.com91958362011-06-13 17:58:13 +0000549};
550
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000551bool GrContext::doOffscreenAA(GrDrawTarget* target,
552 const GrPaint& paint,
553 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000554#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000555 return false;
556#else
557 if (!paint.fAntiAlias) {
558 return false;
559 }
560 if (isLines && fGpu->supportsAALines()) {
561 return false;
562 }
563 if (target->getRenderTarget()->isMultisampled()) {
564 return false;
565 }
566 // we have to be sure that the blend equation is expressible
567 // as simple src / dst coeffecients when the source
568 // is already modulated by the coverage fraction.
569 // We could use dual-source blending to get the correct per-pixel
570 // dst coeffecient for the remaining cases.
571 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
572 kOne_BlendCoeff != paint.fDstBlendCoeff &&
573 kISA_BlendCoeff != paint.fDstBlendCoeff) {
574 return false;
575 }
576 return true;
577#endif
578}
579
bsalomon@google.com91958362011-06-13 17:58:13 +0000580bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000581 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000582 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000583 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000584 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000585
586 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000587
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000588 GrAssert(NULL == record->fEntry0);
589 GrAssert(NULL == record->fEntry1);
bsalomon@google.com91958362011-06-13 17:58:13 +0000590 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000591
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000592 int boundW = boundRect.width();
593 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000594
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000595 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000596
597 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
598 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
599
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000600 if (requireStencil) {
601 desc.fFlags = kRenderTarget_GrTextureFlagBit;
602 } else {
603 desc.fFlags = kRenderTarget_GrTextureFlagBit |
604 kNoStencil_GrTextureFlagBit;
605 }
606
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000607 desc.fFormat = kRGBA_8888_GrPixelConfig;
608
bsalomon@google.com91958362011-06-13 17:58:13 +0000609 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000610 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000611 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000612 desc.fAALevel = kMed_GrAALevel;
613 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000614 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
615 OffscreenRecord::k4x4SinglePass_Downsample :
616 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000617 record->fScale = OFFSCREEN_SSAA_SCALE;
618 // both downsample paths assume this
619 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000620 desc.fAALevel = kNone_GrAALevel;
621 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000622 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
623 // of simple circles?
624 if (pr) {
625 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
626 }
627
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000628 desc.fWidth *= record->fScale;
629 desc.fHeight *= record->fScale;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000630
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000631 record->fEntry0 = this->findApproximateKeylessTexture(desc);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000632 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000633 return false;
634 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000635 // the approximate lookup might have given us some slop space, might as well
636 // use it when computing the tiles size.
637 // these are scale values, will adjust after considering
638 // the possible second offscreen.
639 record->fTileSizeX = record->fEntry0->texture()->width();
640 record->fTileSizeY = record->fEntry0->texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000641
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000642 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000643 desc.fWidth /= 2;
644 desc.fHeight /= 2;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000645 record->fEntry1 = this->findApproximateKeylessTexture(desc);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000646 if (NULL == record->fEntry1) {
647 this->unlockTexture(record->fEntry0);
648 record->fEntry0 = NULL;
649 return false;
650 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000651 record->fTileSizeX = GrMin(record->fTileSizeX,
652 2 * record->fEntry0->texture()->width());
653 record->fTileSizeY = GrMin(record->fTileSizeY,
654 2 * record->fEntry0->texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000655 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000656 record->fTileSizeX /= record->fScale;
657 record->fTileSizeY /= record->fScale;
658
659 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
660 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
661
tomhudson@google.com237a4612011-07-19 15:44:00 +0000662 record->fClip = target->getClip();
663
bsalomon@google.com91958362011-06-13 17:58:13 +0000664 target->saveCurrentDrawState(&record->fSavedState);
665 return true;
666}
667
668void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
669 const GrIRect& boundRect,
670 int tileX, int tileY,
671 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000672
673 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
674 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000675
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000676 GrPaint tempPaint;
677 tempPaint.reset();
678 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000679 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000680
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000681 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000682 int left = boundRect.fLeft + tileX * record->fTileSizeX;
683 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000684 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000685 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000686 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000687 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000688 target->postConcatViewMatrix(scaleM);
689
bsalomon@google.com91958362011-06-13 17:58:13 +0000690 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000691 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000692 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000693 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000694 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
695 record->fScale * h);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000696 target->setClip(GrClip(clear));
bsalomon@google.com91958362011-06-13 17:58:13 +0000697#if 0
698 // visualize tile boundaries by setting edges of offscreen to white
699 // and interior to tranparent. black.
700 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000701
bsalomon@google.com91958362011-06-13 17:58:13 +0000702 static const int gOffset = 2;
703 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
704 record->fScale * w - gOffset,
705 record->fScale * h - gOffset);
706 target->clear(&clear2, 0x0);
707#else
708 target->clear(&clear, 0x0);
709#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000710}
711
bsalomon@google.com91958362011-06-13 17:58:13 +0000712void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000713 const GrPaint& paint,
714 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000715 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000716 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000717 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000718 GrAssert(NULL != record->fEntry0);
bsalomon@google.comee435122011-07-01 14:57:55 +0000719 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000720 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000721 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
722 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000723 tileRect.fRight = (tileX == record->fTileCountX-1) ?
724 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000725 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000726 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
727 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000728 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000730 GrSamplerState::Filter filter;
731 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
732 filter = GrSamplerState::k4x4Downsample_Filter;
733 } else {
734 filter = GrSamplerState::kBilinear_Filter;
735 }
736
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000737 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000738 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000739 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000740
741 GrTexture* src = record->fEntry0->texture();
742 int scale;
743
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000744 enum {
745 kOffscreenStage = GrPaint::kTotalStages,
746 };
747
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000748 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
749 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000750 scale = 2;
751 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
752
753 // Do 2x2 downsample from first to second
754 target->setTexture(kOffscreenStage, src);
755 target->setRenderTarget(dst);
756 target->setViewMatrix(GrMatrix::I());
757 sampleM.setScale(scale * GR_Scalar1 / src->width(),
758 scale * GR_Scalar1 / src->height());
759 sampler.setMatrix(sampleM);
760 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000761 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
762 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000763 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
764
765 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000766 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000767 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000768 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000769 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000770 } else {
771 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
772 record->fDownsample);
773 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000774 }
775
bsalomon@google.com91958362011-06-13 17:58:13 +0000776 // setup for draw back to main RT, we use the original
777 // draw state setup by the caller plus an additional coverage
778 // stage to handle the AA resolve. Also, we use an identity
779 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000780 int stageMask = paint.getActiveStageMask();
781
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000782 target->restoreDrawState(record->fSavedState);
tomhudson@google.com237a4612011-07-19 15:44:00 +0000783 target->setClip(record->fClip);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000784
785 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000786 GrMatrix invVM;
787 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000788 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000789 }
790 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000791 // This is important when tiling, otherwise second tile's
792 // pass 1 view matrix will be incorrect.
793 GrDrawTarget::AutoViewMatrixRestore avmr(target);
794
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000795 target->setViewMatrix(GrMatrix::I());
796
797 target->setTexture(kOffscreenStage, src);
798 sampleM.setScale(scale * GR_Scalar1 / src->width(),
799 scale * GR_Scalar1 / src->height());
800 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000801 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000802 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000803 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000804
reed@google.com20efde72011-05-09 17:00:02 +0000805 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000806 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000807 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000808 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000809}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000810
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000811void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
812 GrPathRenderer* pr,
813 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000814 this->unlockTexture(record->fEntry0);
815 record->fEntry0 = NULL;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000816 if (pr) {
817 // Counterpart of scale() in prepareForOffscreenAA()
818 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
819 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000820 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000821 this->unlockTexture(record->fEntry1);
822 record->fEntry1 = NULL;
823 }
824 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000825}
826
827////////////////////////////////////////////////////////////////////////////////
828
bsalomon@google.com27847de2011-02-22 20:59:41 +0000829/* create a triangle strip that strokes the specified triangle. There are 8
830 unique vertices, but we repreat the last 2 to close up. Alternatively we
831 could use an indices array, and then only send 8 verts, but not sure that
832 would be faster.
833 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000834static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000835 GrScalar width) {
836 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000837 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000838
839 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
840 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
841 verts[2].set(rect.fRight - rad, rect.fTop + rad);
842 verts[3].set(rect.fRight + rad, rect.fTop - rad);
843 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
844 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
845 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
846 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
847 verts[8] = verts[0];
848 verts[9] = verts[1];
849}
850
bsalomon@google.com205d4602011-04-25 12:43:45 +0000851static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000852 // FIXME: This was copied from SkGpuDevice, seems like
853 // we should have already smeared a in caller if that
854 // is what is desired.
855 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000856 unsigned a = GrColorUnpackA(paint.fColor);
857 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000858 } else {
859 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000860 }
861}
862
863static void setInsetFan(GrPoint* pts, size_t stride,
864 const GrRect& r, GrScalar dx, GrScalar dy) {
865 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
866}
867
868static const uint16_t gFillAARectIdx[] = {
869 0, 1, 5, 5, 4, 0,
870 1, 2, 6, 6, 5, 1,
871 2, 3, 7, 7, 6, 2,
872 3, 0, 4, 4, 7, 3,
873 4, 5, 6, 6, 7, 4,
874};
875
876int GrContext::aaFillRectIndexCount() const {
877 return GR_ARRAY_COUNT(gFillAARectIdx);
878}
879
880GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
881 if (NULL == fAAFillRectIndexBuffer) {
882 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
883 false);
884 GrAssert(NULL != fAAFillRectIndexBuffer);
885#if GR_DEBUG
886 bool updated =
887#endif
888 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
889 sizeof(gFillAARectIdx));
890 GR_DEBUGASSERT(updated);
891 }
892 return fAAFillRectIndexBuffer;
893}
894
895static const uint16_t gStrokeAARectIdx[] = {
896 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
897 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
898 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
899 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
900
901 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
902 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
903 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
904 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
905
906 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
907 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
908 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
909 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
910};
911
912int GrContext::aaStrokeRectIndexCount() const {
913 return GR_ARRAY_COUNT(gStrokeAARectIdx);
914}
915
916GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
917 if (NULL == fAAStrokeRectIndexBuffer) {
918 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
919 false);
920 GrAssert(NULL != fAAStrokeRectIndexBuffer);
921#if GR_DEBUG
922 bool updated =
923#endif
924 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
925 sizeof(gStrokeAARectIdx));
926 GR_DEBUGASSERT(updated);
927 }
928 return fAAStrokeRectIndexBuffer;
929}
930
931void GrContext::fillAARect(GrDrawTarget* target,
932 const GrPaint& paint,
933 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000934 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
935 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000936
937 size_t vsize = GrDrawTarget::VertexSize(layout);
938
939 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
940
941 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
942
943 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
944 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
945
946 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
947 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
948
949 verts += sizeof(GrPoint);
950 for (int i = 0; i < 4; ++i) {
951 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
952 }
953
954 GrColor innerColor = getColorForMesh(paint);
955 verts += 4 * vsize;
956 for (int i = 0; i < 4; ++i) {
957 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
958 }
959
960 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
961
962 target->drawIndexed(kTriangles_PrimitiveType, 0,
963 0, 8, this->aaFillRectIndexCount());
964}
965
966void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
967 const GrRect& devRect, const GrVec& devStrokeSize) {
968 const GrScalar& dx = devStrokeSize.fX;
969 const GrScalar& dy = devStrokeSize.fY;
970 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
971 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
972
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000973 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
974 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000975
976 GrScalar spare;
977 {
978 GrScalar w = devRect.width() - dx;
979 GrScalar h = devRect.height() - dy;
980 spare = GrMin(w, h);
981 }
982
983 if (spare <= 0) {
984 GrRect r(devRect);
985 r.inset(-rx, -ry);
986 fillAARect(target, paint, r);
987 return;
988 }
989
990 size_t vsize = GrDrawTarget::VertexSize(layout);
991
992 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
993
994 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
995
996 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
997 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
998 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
999 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
1000
1001 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1002 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1003 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1004 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1005
1006 verts += sizeof(GrPoint);
1007 for (int i = 0; i < 4; ++i) {
1008 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1009 }
1010
1011 GrColor innerColor = getColorForMesh(paint);
1012 verts += 4 * vsize;
1013 for (int i = 0; i < 8; ++i) {
1014 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1015 }
1016
1017 verts += 8 * vsize;
1018 for (int i = 0; i < 8; ++i) {
1019 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1020 }
1021
1022 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1023 target->drawIndexed(kTriangles_PrimitiveType,
1024 0, 0, 16, aaStrokeRectIndexCount());
1025}
1026
reed@google.com20efde72011-05-09 17:00:02 +00001027/**
1028 * Returns true if the rects edges are integer-aligned.
1029 */
1030static bool isIRect(const GrRect& r) {
1031 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1032 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1033}
1034
bsalomon@google.com205d4602011-04-25 12:43:45 +00001035static bool apply_aa_to_rect(GrDrawTarget* target,
1036 GrGpu* gpu,
1037 const GrPaint& paint,
1038 const GrRect& rect,
1039 GrScalar width,
1040 const GrMatrix* matrix,
1041 GrMatrix* combinedMatrix,
1042 GrRect* devRect) {
1043 // we use a simple alpha ramp to do aa on axis-aligned rects
1044 // do AA with alpha ramp if the caller requested AA, the rect
1045 // will be axis-aligned,the render target is not
1046 // multisampled, and the rect won't land on integer coords.
1047
1048 if (!paint.fAntiAlias) {
1049 return false;
1050 }
1051
1052 if (target->getRenderTarget()->isMultisampled()) {
1053 return false;
1054 }
1055
1056 if (0 == width && gpu->supportsAALines()) {
1057 return false;
1058 }
1059
1060 if (!target->getViewMatrix().preservesAxisAlignment()) {
1061 return false;
1062 }
1063
1064 if (NULL != matrix &&
1065 !matrix->preservesAxisAlignment()) {
1066 return false;
1067 }
1068
1069 *combinedMatrix = target->getViewMatrix();
1070 if (NULL != matrix) {
1071 combinedMatrix->preConcat(*matrix);
1072 GrAssert(combinedMatrix->preservesAxisAlignment());
1073 }
1074
1075 combinedMatrix->mapRect(devRect, rect);
1076 devRect->sort();
1077
1078 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001079 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001080 } else {
1081 return true;
1082 }
1083}
1084
bsalomon@google.com27847de2011-02-22 20:59:41 +00001085void GrContext::drawRect(const GrPaint& paint,
1086 const GrRect& rect,
1087 GrScalar width,
1088 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001089 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001090
1091 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001092 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001093
bsalomon@google.com205d4602011-04-25 12:43:45 +00001094 GrRect devRect = rect;
1095 GrMatrix combinedMatrix;
1096 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1097 &combinedMatrix, &devRect);
1098
1099 if (doAA) {
1100 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001101 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001102 GrMatrix inv;
1103 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001104 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001105 }
1106 }
1107 target->setViewMatrix(GrMatrix::I());
1108 if (width >= 0) {
1109 GrVec strokeSize;;
1110 if (width > 0) {
1111 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001112 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001113 strokeSize.setAbs(strokeSize);
1114 } else {
1115 strokeSize.set(GR_Scalar1, GR_Scalar1);
1116 }
1117 strokeAARect(target, paint, devRect, strokeSize);
1118 } else {
1119 fillAARect(target, paint, devRect);
1120 }
1121 return;
1122 }
1123
bsalomon@google.com27847de2011-02-22 20:59:41 +00001124 if (width >= 0) {
1125 // TODO: consider making static vertex buffers for these cases.
1126 // Hairline could be done by just adding closing vertex to
1127 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001128 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1129
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130 static const int worstCaseVertCount = 10;
1131 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1132
1133 if (!geo.succeeded()) {
1134 return;
1135 }
1136
1137 GrPrimitiveType primType;
1138 int vertCount;
1139 GrPoint* vertex = geo.positions();
1140
1141 if (width > 0) {
1142 vertCount = 10;
1143 primType = kTriangleStrip_PrimitiveType;
1144 setStrokeRectStrip(vertex, rect, width);
1145 } else {
1146 // hairline
1147 vertCount = 5;
1148 primType = kLineStrip_PrimitiveType;
1149 vertex[0].set(rect.fLeft, rect.fTop);
1150 vertex[1].set(rect.fRight, rect.fTop);
1151 vertex[2].set(rect.fRight, rect.fBottom);
1152 vertex[3].set(rect.fLeft, rect.fBottom);
1153 vertex[4].set(rect.fLeft, rect.fTop);
1154 }
1155
1156 GrDrawTarget::AutoViewMatrixRestore avmr;
1157 if (NULL != matrix) {
1158 avmr.set(target);
1159 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001160 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001161 }
1162
1163 target->drawNonIndexed(primType, 0, vertCount);
1164 } else {
1165 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001166 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1167
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001168 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001169 fGpu->getUnitSquareVertexBuffer());
1170 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1171 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001172 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001173 0, rect.height(), rect.fTop,
1174 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001175
1176 if (NULL != matrix) {
1177 m.postConcat(*matrix);
1178 }
1179
1180 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001181 target->preConcatSamplerMatrices(stageMask, m);
1182
bsalomon@google.com27847de2011-02-22 20:59:41 +00001183 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1184 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001185 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001186 #endif
1187 }
1188}
1189
1190void GrContext::drawRectToRect(const GrPaint& paint,
1191 const GrRect& dstRect,
1192 const GrRect& srcRect,
1193 const GrMatrix* dstMatrix,
1194 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001195 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001196
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001197 // srcRect refers to paint's first texture
1198 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001199 drawRect(paint, dstRect, -1, dstMatrix);
1200 return;
1201 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001202
bsalomon@google.com27847de2011-02-22 20:59:41 +00001203 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1204
1205#if GR_STATIC_RECT_VB
1206 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001207
1208 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001209 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1210
1211 GrMatrix m;
1212
1213 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1214 0, dstRect.height(), dstRect.fTop,
1215 0, 0, GrMatrix::I()[8]);
1216 if (NULL != dstMatrix) {
1217 m.postConcat(*dstMatrix);
1218 }
1219 target->preConcatViewMatrix(m);
1220
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001221 // srcRect refers to first stage
1222 int otherStageMask = paint.getActiveStageMask() &
1223 (~(1 << GrPaint::kFirstTextureStage));
1224 if (otherStageMask) {
1225 target->preConcatSamplerMatrices(otherStageMask, m);
1226 }
1227
bsalomon@google.com27847de2011-02-22 20:59:41 +00001228 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1229 0, srcRect.height(), srcRect.fTop,
1230 0, 0, GrMatrix::I()[8]);
1231 if (NULL != srcMatrix) {
1232 m.postConcat(*srcMatrix);
1233 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001234 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001235
1236 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1237 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1238#else
1239
1240 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001241#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001242 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001243#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001244 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1245#endif
1246
1247 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1248 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1249 srcRects[0] = &srcRect;
1250 srcMatrices[0] = srcMatrix;
1251
1252 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1253#endif
1254}
1255
1256void GrContext::drawVertices(const GrPaint& paint,
1257 GrPrimitiveType primitiveType,
1258 int vertexCount,
1259 const GrPoint positions[],
1260 const GrPoint texCoords[],
1261 const GrColor colors[],
1262 const uint16_t indices[],
1263 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001264 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001265
1266 GrDrawTarget::AutoReleaseGeometry geo;
1267
1268 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1269
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001270 bool hasTexCoords[GrPaint::kTotalStages] = {
1271 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1272 0 // remaining stages use positions
1273 };
1274
1275 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001276
1277 if (NULL != colors) {
1278 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001279 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001280 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001281
1282 if (sizeof(GrPoint) != vertexSize) {
1283 if (!geo.set(target, layout, vertexCount, 0)) {
1284 GrPrintf("Failed to get space for vertices!");
1285 return;
1286 }
1287 int texOffsets[GrDrawTarget::kMaxTexCoords];
1288 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001289 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1290 texOffsets,
1291 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001292 void* curVertex = geo.vertices();
1293
1294 for (int i = 0; i < vertexCount; ++i) {
1295 *((GrPoint*)curVertex) = positions[i];
1296
1297 if (texOffsets[0] > 0) {
1298 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1299 }
1300 if (colorOffset > 0) {
1301 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1302 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001303 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001304 }
1305 } else {
1306 target->setVertexSourceToArray(layout, positions, vertexCount);
1307 }
1308
bsalomon@google.com91958362011-06-13 17:58:13 +00001309 // we don't currently apply offscreen AA to this path. Need improved
1310 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001311
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001312 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001313 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001314 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001315 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001316 target->drawNonIndexed(primitiveType, 0, vertexCount);
1317 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001318}
1319
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001320///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001321
reed@google.com07f3ee12011-05-16 17:21:57 +00001322void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1323 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324
bsalomon@google.com27847de2011-02-22 20:59:41 +00001325 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comee435122011-07-01 14:57:55 +00001326 GrPathRenderer* pr = this->getPathRenderer(path, fill);
1327 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1328 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001329
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001330 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001331 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001332
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001333 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001334
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001335 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001336 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1337 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001338 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001339 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001340 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001341 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001342 return;
1343 }
1344 }
reed@google.com70c136e2011-06-03 19:51:26 +00001345
reed@google.com07f3ee12011-05-16 17:21:57 +00001346 GrRect pathBounds = path.getBounds();
1347 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001348 if (NULL != translate) {
1349 pathBounds.offset(*translate);
1350 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001351 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001352 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001353 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001354 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001355 return;
1356 }
1357 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001358 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001359 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1360 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001361 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1362 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1363 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001364 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001365 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1366 }
1367 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001368 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001369 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001370 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1371 GrRect rect;
1372 if (clipIBounds.fTop < bound.fTop) {
1373 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1374 clipIBounds.fRight, bound.fTop);
1375 target->drawSimpleRect(rect, NULL, stageMask);
1376 }
1377 if (clipIBounds.fLeft < bound.fLeft) {
1378 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1379 bound.fLeft, bound.fBottom);
1380 target->drawSimpleRect(rect, NULL, stageMask);
1381 }
1382 if (clipIBounds.fRight > bound.fRight) {
1383 rect.setLTRB(bound.fRight, bound.fTop,
1384 clipIBounds.fRight, bound.fBottom);
1385 target->drawSimpleRect(rect, NULL, stageMask);
1386 }
1387 if (clipIBounds.fBottom > bound.fBottom) {
1388 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1389 clipIBounds.fRight, clipIBounds.fBottom);
1390 target->drawSimpleRect(rect, NULL, stageMask);
1391 }
1392 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001393 return;
1394 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001395 }
1396 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001398
bsalomon@google.com27847de2011-02-22 20:59:41 +00001399////////////////////////////////////////////////////////////////////////////////
1400
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001401void GrContext::flush(int flagsBitfield) {
1402 if (kDiscard_FlushBit & flagsBitfield) {
1403 fDrawBuffer->reset();
1404 } else {
1405 flushDrawBuffer();
1406 }
1407
1408 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001409 fGpu->forceRenderTargetFlush();
1410 }
1411}
1412
1413void GrContext::flushText() {
1414 if (kText_DrawCategory == fLastDrawCategory) {
1415 flushDrawBuffer();
1416 }
1417}
1418
1419void GrContext::flushDrawBuffer() {
1420#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001421 if (fDrawBuffer) {
1422 fDrawBuffer->playback(fGpu);
1423 fDrawBuffer->reset();
1424 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001425#endif
1426}
1427
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001428bool GrContext::readTexturePixels(GrTexture* texture,
1429 int left, int top, int width, int height,
1430 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001431 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001432
1433 // TODO: code read pixels for textures that aren't rendertargets
1434
1435 this->flush();
1436 GrRenderTarget* target = texture->asRenderTarget();
1437 if (NULL != target) {
1438 return fGpu->readPixels(target,
1439 left, top, width, height,
1440 config, buffer);
1441 } else {
1442 return false;
1443 }
1444}
1445
1446bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1447 int left, int top, int width, int height,
1448 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001449 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001450 uint32_t flushFlags = 0;
1451 if (NULL == target) {
1452 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1453 }
1454
1455 this->flush(flushFlags);
1456 return fGpu->readPixels(target,
1457 left, top, width, height,
1458 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001459}
1460
1461void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001462 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001464 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001465
1466 // TODO: when underlying api has a direct way to do this we should use it
1467 // (e.g. glDrawPixels on desktop GL).
1468
bsalomon@google.com5c638652011-07-18 19:31:59 +00001469 this->flush(true);
1470
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001471 const GrTextureDesc desc = {
1472 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001473 };
bsalomon@google.com5c638652011-07-18 19:31:59 +00001474 GrAutoUnlockTextureEntry aute(this,
1475 this->findApproximateKeylessTexture(desc));
1476 GrTexture* texture = aute.texture();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001477 if (NULL == texture) {
1478 return;
1479 }
bsalomon@google.com5c638652011-07-18 19:31:59 +00001480 texture->uploadTextureData(0, 0, width, height, buffer, stride);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001481
bsalomon@google.com27847de2011-02-22 20:59:41 +00001482 GrDrawTarget::AutoStateRestore asr(fGpu);
1483
1484 GrMatrix matrix;
1485 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1486 fGpu->setViewMatrix(matrix);
1487
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001488 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001489 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1490 fGpu->setAlpha(0xFF);
1491 fGpu->setBlendFunc(kOne_BlendCoeff,
1492 kZero_BlendCoeff);
1493 fGpu->setTexture(0, texture);
1494
1495 GrSamplerState sampler;
1496 sampler.setClampNoFilter();
bsalomon@google.com5c638652011-07-18 19:31:59 +00001497 matrix.setIDiv(texture->width(), texture->height());
bsalomon@google.com27847de2011-02-22 20:59:41 +00001498 sampler.setMatrix(matrix);
1499 fGpu->setSamplerState(0, sampler);
1500
1501 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1502 static const int VCOUNT = 4;
1503
1504 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1505 if (!geo.succeeded()) {
1506 return;
1507 }
1508 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1509 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1510}
1511////////////////////////////////////////////////////////////////////////////////
1512
1513void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001514
1515 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1516 int s = i + GrPaint::kFirstTextureStage;
1517 target->setTexture(s, paint.getTexture(i));
1518 target->setSamplerState(s, *paint.getTextureSampler(i));
1519 }
1520
1521 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1522
1523 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1524 int s = i + GrPaint::kFirstMaskStage;
1525 target->setTexture(s, paint.getMask(i));
1526 target->setSamplerState(s, *paint.getMaskSampler(i));
1527 }
1528
bsalomon@google.com27847de2011-02-22 20:59:41 +00001529 target->setColor(paint.fColor);
1530
1531 if (paint.fDither) {
1532 target->enableState(GrDrawTarget::kDither_StateBit);
1533 } else {
1534 target->disableState(GrDrawTarget::kDither_StateBit);
1535 }
1536 if (paint.fAntiAlias) {
1537 target->enableState(GrDrawTarget::kAntialias_StateBit);
1538 } else {
1539 target->disableState(GrDrawTarget::kAntialias_StateBit);
1540 }
1541 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001542 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001543}
1544
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001545GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001546 DrawCategory category) {
1547 if (category != fLastDrawCategory) {
1548 flushDrawBuffer();
1549 fLastDrawCategory = category;
1550 }
1551 SetPaint(paint, fGpu);
1552 GrDrawTarget* target = fGpu;
1553 switch (category) {
1554 case kText_DrawCategory:
1555#if DEFER_TEXT_RENDERING
1556 target = fDrawBuffer;
1557 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1558#else
1559 target = fGpu;
1560#endif
1561 break;
1562 case kUnbuffered_DrawCategory:
1563 target = fGpu;
1564 break;
1565 case kBuffered_DrawCategory:
1566 target = fDrawBuffer;
1567 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1568 break;
1569 }
1570 return target;
1571}
1572
1573////////////////////////////////////////////////////////////////////////////////
1574
bsalomon@google.com27847de2011-02-22 20:59:41 +00001575void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001576 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001577 fGpu->setRenderTarget(target);
1578}
1579
1580GrRenderTarget* GrContext::getRenderTarget() {
1581 return fGpu->getRenderTarget();
1582}
1583
1584const GrRenderTarget* GrContext::getRenderTarget() const {
1585 return fGpu->getRenderTarget();
1586}
1587
1588const GrMatrix& GrContext::getMatrix() const {
1589 return fGpu->getViewMatrix();
1590}
1591
1592void GrContext::setMatrix(const GrMatrix& m) {
1593 fGpu->setViewMatrix(m);
1594}
1595
1596void GrContext::concatMatrix(const GrMatrix& m) const {
1597 fGpu->preConcatViewMatrix(m);
1598}
1599
1600static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1601 intptr_t mask = 1 << shift;
1602 if (pred) {
1603 bits |= mask;
1604 } else {
1605 bits &= ~mask;
1606 }
1607 return bits;
1608}
1609
1610void GrContext::resetStats() {
1611 fGpu->resetStats();
1612}
1613
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001614const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001615 return fGpu->getStats();
1616}
1617
1618void GrContext::printStats() const {
1619 fGpu->printStats();
1620}
1621
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001622GrContext::GrContext(GrGpu* gpu) :
1623 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1624 gpu->supportsStencilWrapOps()) {
1625
bsalomon@google.com27847de2011-02-22 20:59:41 +00001626 fGpu = gpu;
1627 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001628 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001629
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001630 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1631 fGpu->setClipPathRenderer(fCustomPathRenderer);
1632
bsalomon@google.com27847de2011-02-22 20:59:41 +00001633 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1634 MAX_TEXTURE_CACHE_BYTES);
1635 fFontCache = new GrFontCache(fGpu);
1636
1637 fLastDrawCategory = kUnbuffered_DrawCategory;
1638
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001639 fDrawBuffer = NULL;
1640 fDrawBufferVBAllocPool = NULL;
1641 fDrawBufferIBAllocPool = NULL;
1642
bsalomon@google.com205d4602011-04-25 12:43:45 +00001643 fAAFillRectIndexBuffer = NULL;
1644 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001645
1646 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1647 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1648 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1649 }
1650 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001651
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001652 this->setupDrawBuffer();
1653}
1654
1655void GrContext::setupDrawBuffer() {
1656
1657 GrAssert(NULL == fDrawBuffer);
1658 GrAssert(NULL == fDrawBufferVBAllocPool);
1659 GrAssert(NULL == fDrawBufferIBAllocPool);
1660
bsalomon@google.com27847de2011-02-22 20:59:41 +00001661#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001662 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001663 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001664 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1665 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001666 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001667 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001668 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001669 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1670
1671 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1672 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001673#endif
1674
1675#if BATCH_RECT_TO_RECT
1676 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1677#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001678}
1679
bsalomon@google.com27847de2011-02-22 20:59:41 +00001680GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1681 GrDrawTarget* target;
1682#if DEFER_TEXT_RENDERING
1683 target = prepareToDraw(paint, kText_DrawCategory);
1684#else
1685 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1686#endif
1687 SetPaint(paint, target);
1688 return target;
1689}
1690
1691const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1692 return fGpu->getQuadIndexBuffer();
1693}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001694
bsalomon@google.comee435122011-07-01 14:57:55 +00001695GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001696 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001697 if (NULL != fCustomPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +00001698 fCustomPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001699 return fCustomPathRenderer;
1700 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +00001701 GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001702 return &fDefaultPathRenderer;
1703 }
1704}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001705
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001706void GrContext::convolveInX(GrTexture* texture,
1707 const SkRect& rect,
1708 const float* kernel,
1709 int kernelWidth) {
1710 float imageIncrement[2] = {1.0f / texture->width(), 0.0f};
1711 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1712}
1713
1714void GrContext::convolveInY(GrTexture* texture,
1715 const SkRect& rect,
1716 const float* kernel,
1717 int kernelWidth) {
1718 float imageIncrement[2] = {0.0f, 1.0f / texture->height()};
1719 convolve(texture, rect, imageIncrement, kernel, kernelWidth);
1720}
1721
1722void GrContext::convolve(GrTexture* texture,
1723 const SkRect& rect,
1724 float imageIncrement[2],
1725 const float* kernel,
1726 int kernelWidth) {
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001727 GrDrawTarget::AutoStateRestore asr(fGpu);
1728 GrMatrix sampleM;
1729 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1730 GrSamplerState::kClamp_WrapMode,
1731 GrSamplerState::kConvolution_Filter);
1732 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001733 sampleM.setScale(GR_Scalar1 / texture->width(),
1734 GR_Scalar1 / texture->height());
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001735 sampler.setMatrix(sampleM);
1736 fGpu->setSamplerState(0, sampler);
1737 fGpu->setViewMatrix(GrMatrix::I());
senorblanco@chromium.orgaadd9f82011-07-12 19:44:51 +00001738 fGpu->setTexture(0, texture);
senorblanco@chromium.org2ce9a042011-07-22 15:31:14 +00001739 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001740 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1741}