blob: 092b0ba9e2b846a263f086273e3005301237db6e [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;
548};
549
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000550bool GrContext::doOffscreenAA(GrDrawTarget* target,
551 const GrPaint& paint,
552 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000553#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000554 return false;
555#else
556 if (!paint.fAntiAlias) {
557 return false;
558 }
559 if (isLines && fGpu->supportsAALines()) {
560 return false;
561 }
562 if (target->getRenderTarget()->isMultisampled()) {
563 return false;
564 }
565 // we have to be sure that the blend equation is expressible
566 // as simple src / dst coeffecients when the source
567 // is already modulated by the coverage fraction.
568 // We could use dual-source blending to get the correct per-pixel
569 // dst coeffecient for the remaining cases.
570 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
571 kOne_BlendCoeff != paint.fDstBlendCoeff &&
572 kISA_BlendCoeff != paint.fDstBlendCoeff) {
573 return false;
574 }
575 return true;
576#endif
577}
578
bsalomon@google.com91958362011-06-13 17:58:13 +0000579bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000580 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000581 const GrIRect& boundRect,
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000582 GrPathRenderer* pr,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000583 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000584
585 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000586
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000587 GrAssert(NULL == record->fEntry0);
588 GrAssert(NULL == record->fEntry1);
bsalomon@google.com91958362011-06-13 17:58:13 +0000589 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000590
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000591 int boundW = boundRect.width();
592 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000593
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000594 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000595
596 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
597 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
598
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000599 if (requireStencil) {
600 desc.fFlags = kRenderTarget_GrTextureFlagBit;
601 } else {
602 desc.fFlags = kRenderTarget_GrTextureFlagBit |
603 kNoStencil_GrTextureFlagBit;
604 }
605
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000606 desc.fFormat = kRGBA_8888_GrPixelConfig;
607
bsalomon@google.com91958362011-06-13 17:58:13 +0000608 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000609 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000610 record->fScale = 1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000611 desc.fAALevel = kMed_GrAALevel;
612 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000613 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
614 OffscreenRecord::k4x4SinglePass_Downsample :
615 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000616 record->fScale = OFFSCREEN_SSAA_SCALE;
617 // both downsample paths assume this
618 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000619 desc.fAALevel = kNone_GrAALevel;
620 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000621 // Avoid overtesselating paths in AA buffers; may unduly reduce quality
622 // of simple circles?
623 if (pr) {
624 //pr->scaleCurveTolerance(GrIntToScalar(record->fScale));
625 }
626
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000627 desc.fWidth *= record->fScale;
628 desc.fHeight *= record->fScale;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000629
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000630 record->fEntry0 = this->findApproximateKeylessTexture(desc);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000631 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000632 return false;
633 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000634 // the approximate lookup might have given us some slop space, might as well
635 // use it when computing the tiles size.
636 // these are scale values, will adjust after considering
637 // the possible second offscreen.
638 record->fTileSizeX = record->fEntry0->texture()->width();
639 record->fTileSizeY = record->fEntry0->texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000640
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000641 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000642 desc.fWidth /= 2;
643 desc.fHeight /= 2;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000644 record->fEntry1 = this->findApproximateKeylessTexture(desc);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000645 if (NULL == record->fEntry1) {
646 this->unlockTexture(record->fEntry0);
647 record->fEntry0 = NULL;
648 return false;
649 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000650 record->fTileSizeX = GrMin(record->fTileSizeX,
651 2 * record->fEntry0->texture()->width());
652 record->fTileSizeY = GrMin(record->fTileSizeY,
653 2 * record->fEntry0->texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000654 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000655 record->fTileSizeX /= record->fScale;
656 record->fTileSizeY /= record->fScale;
657
658 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
659 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
660
bsalomon@google.com91958362011-06-13 17:58:13 +0000661 target->saveCurrentDrawState(&record->fSavedState);
662 return true;
663}
664
665void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
666 const GrIRect& boundRect,
667 int tileX, int tileY,
668 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000669
670 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
671 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000672
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000673 GrPaint tempPaint;
674 tempPaint.reset();
675 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000676 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000677
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000678 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000679 int left = boundRect.fLeft + tileX * record->fTileSizeX;
680 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000681 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000682 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000683 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000684 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000685 target->postConcatViewMatrix(scaleM);
686
687 // clip gets applied in second pass
688 target->disableState(GrDrawTarget::kClip_StateBit);
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);
696#if 0
697 // visualize tile boundaries by setting edges of offscreen to white
698 // and interior to tranparent. black.
699 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000700
bsalomon@google.com91958362011-06-13 17:58:13 +0000701 static const int gOffset = 2;
702 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
703 record->fScale * w - gOffset,
704 record->fScale * h - gOffset);
705 target->clear(&clear2, 0x0);
706#else
707 target->clear(&clear, 0x0);
708#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000709}
710
bsalomon@google.com91958362011-06-13 17:58:13 +0000711void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000712 const GrPaint& paint,
713 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000714 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000715 OffscreenRecord* record) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000716 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000717 GrAssert(NULL != record->fEntry0);
bsalomon@google.comee435122011-07-01 14:57:55 +0000718 GrDrawTarget::AutoGeometryPush agp(target);
bsalomon@google.com91958362011-06-13 17:58:13 +0000719 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000720 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
721 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000722 tileRect.fRight = (tileX == record->fTileCountX-1) ?
723 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000724 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000725 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
726 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000727 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000728
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000729 GrSamplerState::Filter filter;
730 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
731 filter = GrSamplerState::k4x4Downsample_Filter;
732 } else {
733 filter = GrSamplerState::kBilinear_Filter;
734 }
735
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000736 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000737 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000738 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000739
740 GrTexture* src = record->fEntry0->texture();
741 int scale;
742
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000743 enum {
744 kOffscreenStage = GrPaint::kTotalStages,
745 };
746
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000747 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
748 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000749 scale = 2;
750 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
751
752 // Do 2x2 downsample from first to second
753 target->setTexture(kOffscreenStage, src);
754 target->setRenderTarget(dst);
755 target->setViewMatrix(GrMatrix::I());
756 sampleM.setScale(scale * GR_Scalar1 / src->width(),
757 scale * GR_Scalar1 / src->height());
758 sampler.setMatrix(sampleM);
759 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000760 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
761 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000762 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
763
764 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000765 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000766 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000767 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000768 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000769 } else {
770 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
771 record->fDownsample);
772 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000773 }
774
bsalomon@google.com91958362011-06-13 17:58:13 +0000775 // setup for draw back to main RT, we use the original
776 // draw state setup by the caller plus an additional coverage
777 // stage to handle the AA resolve. Also, we use an identity
778 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000779 int stageMask = paint.getActiveStageMask();
780
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000781 target->restoreDrawState(record->fSavedState);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000782
783 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000784 GrMatrix invVM;
785 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000786 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000787 }
788 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000789 // This is important when tiling, otherwise second tile's
790 // pass 1 view matrix will be incorrect.
791 GrDrawTarget::AutoViewMatrixRestore avmr(target);
792
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000793 target->setViewMatrix(GrMatrix::I());
794
795 target->setTexture(kOffscreenStage, src);
796 sampleM.setScale(scale * GR_Scalar1 / src->width(),
797 scale * GR_Scalar1 / src->height());
798 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000799 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000800 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000801 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000802
reed@google.com20efde72011-05-09 17:00:02 +0000803 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000804 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000805 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000806 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000807}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000808
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000809void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
810 GrPathRenderer* pr,
811 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000812 this->unlockTexture(record->fEntry0);
813 record->fEntry0 = NULL;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000814 if (pr) {
815 // Counterpart of scale() in prepareForOffscreenAA()
816 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
817 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000818 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000819 this->unlockTexture(record->fEntry1);
820 record->fEntry1 = NULL;
821 }
822 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000823}
824
825////////////////////////////////////////////////////////////////////////////////
826
bsalomon@google.com27847de2011-02-22 20:59:41 +0000827/* create a triangle strip that strokes the specified triangle. There are 8
828 unique vertices, but we repreat the last 2 to close up. Alternatively we
829 could use an indices array, and then only send 8 verts, but not sure that
830 would be faster.
831 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000832static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000833 GrScalar width) {
834 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000835 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000836
837 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
838 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
839 verts[2].set(rect.fRight - rad, rect.fTop + rad);
840 verts[3].set(rect.fRight + rad, rect.fTop - rad);
841 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
842 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
843 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
844 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
845 verts[8] = verts[0];
846 verts[9] = verts[1];
847}
848
bsalomon@google.com205d4602011-04-25 12:43:45 +0000849static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000850 // FIXME: This was copied from SkGpuDevice, seems like
851 // we should have already smeared a in caller if that
852 // is what is desired.
853 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000854 unsigned a = GrColorUnpackA(paint.fColor);
855 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000856 } else {
857 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000858 }
859}
860
861static void setInsetFan(GrPoint* pts, size_t stride,
862 const GrRect& r, GrScalar dx, GrScalar dy) {
863 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
864}
865
866static const uint16_t gFillAARectIdx[] = {
867 0, 1, 5, 5, 4, 0,
868 1, 2, 6, 6, 5, 1,
869 2, 3, 7, 7, 6, 2,
870 3, 0, 4, 4, 7, 3,
871 4, 5, 6, 6, 7, 4,
872};
873
874int GrContext::aaFillRectIndexCount() const {
875 return GR_ARRAY_COUNT(gFillAARectIdx);
876}
877
878GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
879 if (NULL == fAAFillRectIndexBuffer) {
880 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
881 false);
882 GrAssert(NULL != fAAFillRectIndexBuffer);
883#if GR_DEBUG
884 bool updated =
885#endif
886 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
887 sizeof(gFillAARectIdx));
888 GR_DEBUGASSERT(updated);
889 }
890 return fAAFillRectIndexBuffer;
891}
892
893static const uint16_t gStrokeAARectIdx[] = {
894 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
895 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
896 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
897 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
898
899 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
900 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
901 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
902 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
903
904 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
905 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
906 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
907 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
908};
909
910int GrContext::aaStrokeRectIndexCount() const {
911 return GR_ARRAY_COUNT(gStrokeAARectIdx);
912}
913
914GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
915 if (NULL == fAAStrokeRectIndexBuffer) {
916 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
917 false);
918 GrAssert(NULL != fAAStrokeRectIndexBuffer);
919#if GR_DEBUG
920 bool updated =
921#endif
922 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
923 sizeof(gStrokeAARectIdx));
924 GR_DEBUGASSERT(updated);
925 }
926 return fAAStrokeRectIndexBuffer;
927}
928
929void GrContext::fillAARect(GrDrawTarget* target,
930 const GrPaint& paint,
931 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000932 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
933 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000934
935 size_t vsize = GrDrawTarget::VertexSize(layout);
936
937 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
938
939 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
940
941 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
942 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
943
944 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
945 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
946
947 verts += sizeof(GrPoint);
948 for (int i = 0; i < 4; ++i) {
949 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
950 }
951
952 GrColor innerColor = getColorForMesh(paint);
953 verts += 4 * vsize;
954 for (int i = 0; i < 4; ++i) {
955 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
956 }
957
958 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
959
960 target->drawIndexed(kTriangles_PrimitiveType, 0,
961 0, 8, this->aaFillRectIndexCount());
962}
963
964void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
965 const GrRect& devRect, const GrVec& devStrokeSize) {
966 const GrScalar& dx = devStrokeSize.fX;
967 const GrScalar& dy = devStrokeSize.fY;
968 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
969 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
970
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000971 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
972 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000973
974 GrScalar spare;
975 {
976 GrScalar w = devRect.width() - dx;
977 GrScalar h = devRect.height() - dy;
978 spare = GrMin(w, h);
979 }
980
981 if (spare <= 0) {
982 GrRect r(devRect);
983 r.inset(-rx, -ry);
984 fillAARect(target, paint, r);
985 return;
986 }
987
988 size_t vsize = GrDrawTarget::VertexSize(layout);
989
990 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
991
992 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
993
994 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
995 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
996 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
997 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
998
999 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1000 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1001 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1002 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1003
1004 verts += sizeof(GrPoint);
1005 for (int i = 0; i < 4; ++i) {
1006 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1007 }
1008
1009 GrColor innerColor = getColorForMesh(paint);
1010 verts += 4 * vsize;
1011 for (int i = 0; i < 8; ++i) {
1012 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1013 }
1014
1015 verts += 8 * vsize;
1016 for (int i = 0; i < 8; ++i) {
1017 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1018 }
1019
1020 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1021 target->drawIndexed(kTriangles_PrimitiveType,
1022 0, 0, 16, aaStrokeRectIndexCount());
1023}
1024
reed@google.com20efde72011-05-09 17:00:02 +00001025/**
1026 * Returns true if the rects edges are integer-aligned.
1027 */
1028static bool isIRect(const GrRect& r) {
1029 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1030 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1031}
1032
bsalomon@google.com205d4602011-04-25 12:43:45 +00001033static bool apply_aa_to_rect(GrDrawTarget* target,
1034 GrGpu* gpu,
1035 const GrPaint& paint,
1036 const GrRect& rect,
1037 GrScalar width,
1038 const GrMatrix* matrix,
1039 GrMatrix* combinedMatrix,
1040 GrRect* devRect) {
1041 // we use a simple alpha ramp to do aa on axis-aligned rects
1042 // do AA with alpha ramp if the caller requested AA, the rect
1043 // will be axis-aligned,the render target is not
1044 // multisampled, and the rect won't land on integer coords.
1045
1046 if (!paint.fAntiAlias) {
1047 return false;
1048 }
1049
1050 if (target->getRenderTarget()->isMultisampled()) {
1051 return false;
1052 }
1053
1054 if (0 == width && gpu->supportsAALines()) {
1055 return false;
1056 }
1057
1058 if (!target->getViewMatrix().preservesAxisAlignment()) {
1059 return false;
1060 }
1061
1062 if (NULL != matrix &&
1063 !matrix->preservesAxisAlignment()) {
1064 return false;
1065 }
1066
1067 *combinedMatrix = target->getViewMatrix();
1068 if (NULL != matrix) {
1069 combinedMatrix->preConcat(*matrix);
1070 GrAssert(combinedMatrix->preservesAxisAlignment());
1071 }
1072
1073 combinedMatrix->mapRect(devRect, rect);
1074 devRect->sort();
1075
1076 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001077 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001078 } else {
1079 return true;
1080 }
1081}
1082
bsalomon@google.com27847de2011-02-22 20:59:41 +00001083void GrContext::drawRect(const GrPaint& paint,
1084 const GrRect& rect,
1085 GrScalar width,
1086 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001087 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001088
1089 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001090 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001091
bsalomon@google.com205d4602011-04-25 12:43:45 +00001092 GrRect devRect = rect;
1093 GrMatrix combinedMatrix;
1094 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1095 &combinedMatrix, &devRect);
1096
1097 if (doAA) {
1098 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001099 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001100 GrMatrix inv;
1101 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001102 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001103 }
1104 }
1105 target->setViewMatrix(GrMatrix::I());
1106 if (width >= 0) {
1107 GrVec strokeSize;;
1108 if (width > 0) {
1109 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001110 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001111 strokeSize.setAbs(strokeSize);
1112 } else {
1113 strokeSize.set(GR_Scalar1, GR_Scalar1);
1114 }
1115 strokeAARect(target, paint, devRect, strokeSize);
1116 } else {
1117 fillAARect(target, paint, devRect);
1118 }
1119 return;
1120 }
1121
bsalomon@google.com27847de2011-02-22 20:59:41 +00001122 if (width >= 0) {
1123 // TODO: consider making static vertex buffers for these cases.
1124 // Hairline could be done by just adding closing vertex to
1125 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001126 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1127
bsalomon@google.com27847de2011-02-22 20:59:41 +00001128 static const int worstCaseVertCount = 10;
1129 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1130
1131 if (!geo.succeeded()) {
1132 return;
1133 }
1134
1135 GrPrimitiveType primType;
1136 int vertCount;
1137 GrPoint* vertex = geo.positions();
1138
1139 if (width > 0) {
1140 vertCount = 10;
1141 primType = kTriangleStrip_PrimitiveType;
1142 setStrokeRectStrip(vertex, rect, width);
1143 } else {
1144 // hairline
1145 vertCount = 5;
1146 primType = kLineStrip_PrimitiveType;
1147 vertex[0].set(rect.fLeft, rect.fTop);
1148 vertex[1].set(rect.fRight, rect.fTop);
1149 vertex[2].set(rect.fRight, rect.fBottom);
1150 vertex[3].set(rect.fLeft, rect.fBottom);
1151 vertex[4].set(rect.fLeft, rect.fTop);
1152 }
1153
1154 GrDrawTarget::AutoViewMatrixRestore avmr;
1155 if (NULL != matrix) {
1156 avmr.set(target);
1157 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001158 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001159 }
1160
1161 target->drawNonIndexed(primType, 0, vertCount);
1162 } else {
1163 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001164 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1165
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001166 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001167 fGpu->getUnitSquareVertexBuffer());
1168 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1169 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001170 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001171 0, rect.height(), rect.fTop,
1172 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001173
1174 if (NULL != matrix) {
1175 m.postConcat(*matrix);
1176 }
1177
1178 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001179 target->preConcatSamplerMatrices(stageMask, m);
1180
bsalomon@google.com27847de2011-02-22 20:59:41 +00001181 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1182 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001183 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001184 #endif
1185 }
1186}
1187
1188void GrContext::drawRectToRect(const GrPaint& paint,
1189 const GrRect& dstRect,
1190 const GrRect& srcRect,
1191 const GrMatrix* dstMatrix,
1192 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001193 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001194
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001195 // srcRect refers to paint's first texture
1196 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001197 drawRect(paint, dstRect, -1, dstMatrix);
1198 return;
1199 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001200
bsalomon@google.com27847de2011-02-22 20:59:41 +00001201 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1202
1203#if GR_STATIC_RECT_VB
1204 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001205
1206 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001207 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1208
1209 GrMatrix m;
1210
1211 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1212 0, dstRect.height(), dstRect.fTop,
1213 0, 0, GrMatrix::I()[8]);
1214 if (NULL != dstMatrix) {
1215 m.postConcat(*dstMatrix);
1216 }
1217 target->preConcatViewMatrix(m);
1218
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001219 // srcRect refers to first stage
1220 int otherStageMask = paint.getActiveStageMask() &
1221 (~(1 << GrPaint::kFirstTextureStage));
1222 if (otherStageMask) {
1223 target->preConcatSamplerMatrices(otherStageMask, m);
1224 }
1225
bsalomon@google.com27847de2011-02-22 20:59:41 +00001226 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1227 0, srcRect.height(), srcRect.fTop,
1228 0, 0, GrMatrix::I()[8]);
1229 if (NULL != srcMatrix) {
1230 m.postConcat(*srcMatrix);
1231 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001232 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001233
1234 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1235 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1236#else
1237
1238 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001239#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001240 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001241#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001242 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1243#endif
1244
1245 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1246 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1247 srcRects[0] = &srcRect;
1248 srcMatrices[0] = srcMatrix;
1249
1250 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1251#endif
1252}
1253
1254void GrContext::drawVertices(const GrPaint& paint,
1255 GrPrimitiveType primitiveType,
1256 int vertexCount,
1257 const GrPoint positions[],
1258 const GrPoint texCoords[],
1259 const GrColor colors[],
1260 const uint16_t indices[],
1261 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001262 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001263
1264 GrDrawTarget::AutoReleaseGeometry geo;
1265
1266 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1267
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001268 bool hasTexCoords[GrPaint::kTotalStages] = {
1269 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1270 0 // remaining stages use positions
1271 };
1272
1273 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001274
1275 if (NULL != colors) {
1276 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001277 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001278 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001279
1280 if (sizeof(GrPoint) != vertexSize) {
1281 if (!geo.set(target, layout, vertexCount, 0)) {
1282 GrPrintf("Failed to get space for vertices!");
1283 return;
1284 }
1285 int texOffsets[GrDrawTarget::kMaxTexCoords];
1286 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001287 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1288 texOffsets,
1289 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001290 void* curVertex = geo.vertices();
1291
1292 for (int i = 0; i < vertexCount; ++i) {
1293 *((GrPoint*)curVertex) = positions[i];
1294
1295 if (texOffsets[0] > 0) {
1296 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1297 }
1298 if (colorOffset > 0) {
1299 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1300 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001301 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001302 }
1303 } else {
1304 target->setVertexSourceToArray(layout, positions, vertexCount);
1305 }
1306
bsalomon@google.com91958362011-06-13 17:58:13 +00001307 // we don't currently apply offscreen AA to this path. Need improved
1308 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001309
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001310 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001311 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001312 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001313 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001314 target->drawNonIndexed(primitiveType, 0, vertexCount);
1315 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001316}
1317
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001318///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001319
reed@google.com07f3ee12011-05-16 17:21:57 +00001320void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1321 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001322
bsalomon@google.com27847de2011-02-22 20:59:41 +00001323 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.comee435122011-07-01 14:57:55 +00001324 GrPathRenderer* pr = this->getPathRenderer(path, fill);
1325 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
1326 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001327
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001328 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001329 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001330
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001331 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001332
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001333 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001334 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1335 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001336 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001337 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001338 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001339 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001340 return;
1341 }
1342 }
reed@google.com70c136e2011-06-03 19:51:26 +00001343
reed@google.com07f3ee12011-05-16 17:21:57 +00001344 GrRect pathBounds = path.getBounds();
1345 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001346 if (NULL != translate) {
1347 pathBounds.offset(*translate);
1348 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001349 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001350 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001351 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001352 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001353 return;
1354 }
1355 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001356 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001357 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1358 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001359 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1360 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1361 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
bsalomon@google.comee435122011-07-01 14:57:55 +00001362 pr->drawPath(0);
bsalomon@google.com91958362011-06-13 17:58:13 +00001363 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1364 }
1365 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001366 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001367 if (IsFillInverted(fill) && bound != clipIBounds) {
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001368 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1369 GrRect rect;
1370 if (clipIBounds.fTop < bound.fTop) {
1371 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1372 clipIBounds.fRight, bound.fTop);
1373 target->drawSimpleRect(rect, NULL, stageMask);
1374 }
1375 if (clipIBounds.fLeft < bound.fLeft) {
1376 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1377 bound.fLeft, bound.fBottom);
1378 target->drawSimpleRect(rect, NULL, stageMask);
1379 }
1380 if (clipIBounds.fRight > bound.fRight) {
1381 rect.setLTRB(bound.fRight, bound.fTop,
1382 clipIBounds.fRight, bound.fBottom);
1383 target->drawSimpleRect(rect, NULL, stageMask);
1384 }
1385 if (clipIBounds.fBottom > bound.fBottom) {
1386 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1387 clipIBounds.fRight, clipIBounds.fBottom);
1388 target->drawSimpleRect(rect, NULL, stageMask);
1389 }
1390 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001391 return;
1392 }
bsalomon@google.comee435122011-07-01 14:57:55 +00001393 }
1394 pr->drawPath(stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001396
bsalomon@google.com27847de2011-02-22 20:59:41 +00001397////////////////////////////////////////////////////////////////////////////////
1398
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001399void GrContext::flush(int flagsBitfield) {
1400 if (kDiscard_FlushBit & flagsBitfield) {
1401 fDrawBuffer->reset();
1402 } else {
1403 flushDrawBuffer();
1404 }
1405
1406 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001407 fGpu->forceRenderTargetFlush();
1408 }
1409}
1410
1411void GrContext::flushText() {
1412 if (kText_DrawCategory == fLastDrawCategory) {
1413 flushDrawBuffer();
1414 }
1415}
1416
1417void GrContext::flushDrawBuffer() {
1418#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001419 if (fDrawBuffer) {
1420 fDrawBuffer->playback(fGpu);
1421 fDrawBuffer->reset();
1422 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001423#endif
1424}
1425
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001426bool GrContext::readTexturePixels(GrTexture* texture,
1427 int left, int top, int width, int height,
1428 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001429 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001430
1431 // TODO: code read pixels for textures that aren't rendertargets
1432
1433 this->flush();
1434 GrRenderTarget* target = texture->asRenderTarget();
1435 if (NULL != target) {
1436 return fGpu->readPixels(target,
1437 left, top, width, height,
1438 config, buffer);
1439 } else {
1440 return false;
1441 }
1442}
1443
1444bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1445 int left, int top, int width, int height,
1446 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001447 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001448 uint32_t flushFlags = 0;
1449 if (NULL == target) {
1450 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1451 }
1452
1453 this->flush(flushFlags);
1454 return fGpu->readPixels(target,
1455 left, top, width, height,
1456 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001457}
1458
1459void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001460 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001461 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001462 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001463
1464 // TODO: when underlying api has a direct way to do this we should use it
1465 // (e.g. glDrawPixels on desktop GL).
1466
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001467 const GrTextureDesc desc = {
1468 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001469 };
1470 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1471 if (NULL == texture) {
1472 return;
1473 }
1474
1475 this->flush(true);
1476
1477 GrAutoUnref aur(texture);
1478 GrDrawTarget::AutoStateRestore asr(fGpu);
1479
1480 GrMatrix matrix;
1481 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1482 fGpu->setViewMatrix(matrix);
1483
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001484 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001485 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1486 fGpu->setAlpha(0xFF);
1487 fGpu->setBlendFunc(kOne_BlendCoeff,
1488 kZero_BlendCoeff);
1489 fGpu->setTexture(0, texture);
1490
1491 GrSamplerState sampler;
1492 sampler.setClampNoFilter();
1493 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1494 sampler.setMatrix(matrix);
1495 fGpu->setSamplerState(0, sampler);
1496
1497 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1498 static const int VCOUNT = 4;
1499
1500 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1501 if (!geo.succeeded()) {
1502 return;
1503 }
1504 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1505 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1506}
1507////////////////////////////////////////////////////////////////////////////////
1508
1509void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001510
1511 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1512 int s = i + GrPaint::kFirstTextureStage;
1513 target->setTexture(s, paint.getTexture(i));
1514 target->setSamplerState(s, *paint.getTextureSampler(i));
1515 }
1516
1517 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1518
1519 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1520 int s = i + GrPaint::kFirstMaskStage;
1521 target->setTexture(s, paint.getMask(i));
1522 target->setSamplerState(s, *paint.getMaskSampler(i));
1523 }
1524
bsalomon@google.com27847de2011-02-22 20:59:41 +00001525 target->setColor(paint.fColor);
1526
1527 if (paint.fDither) {
1528 target->enableState(GrDrawTarget::kDither_StateBit);
1529 } else {
1530 target->disableState(GrDrawTarget::kDither_StateBit);
1531 }
1532 if (paint.fAntiAlias) {
1533 target->enableState(GrDrawTarget::kAntialias_StateBit);
1534 } else {
1535 target->disableState(GrDrawTarget::kAntialias_StateBit);
1536 }
1537 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001538 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001539}
1540
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001541GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001542 DrawCategory category) {
1543 if (category != fLastDrawCategory) {
1544 flushDrawBuffer();
1545 fLastDrawCategory = category;
1546 }
1547 SetPaint(paint, fGpu);
1548 GrDrawTarget* target = fGpu;
1549 switch (category) {
1550 case kText_DrawCategory:
1551#if DEFER_TEXT_RENDERING
1552 target = fDrawBuffer;
1553 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1554#else
1555 target = fGpu;
1556#endif
1557 break;
1558 case kUnbuffered_DrawCategory:
1559 target = fGpu;
1560 break;
1561 case kBuffered_DrawCategory:
1562 target = fDrawBuffer;
1563 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1564 break;
1565 }
1566 return target;
1567}
1568
1569////////////////////////////////////////////////////////////////////////////////
1570
bsalomon@google.com27847de2011-02-22 20:59:41 +00001571void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001572 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001573 fGpu->setRenderTarget(target);
1574}
1575
1576GrRenderTarget* GrContext::getRenderTarget() {
1577 return fGpu->getRenderTarget();
1578}
1579
1580const GrRenderTarget* GrContext::getRenderTarget() const {
1581 return fGpu->getRenderTarget();
1582}
1583
1584const GrMatrix& GrContext::getMatrix() const {
1585 return fGpu->getViewMatrix();
1586}
1587
1588void GrContext::setMatrix(const GrMatrix& m) {
1589 fGpu->setViewMatrix(m);
1590}
1591
1592void GrContext::concatMatrix(const GrMatrix& m) const {
1593 fGpu->preConcatViewMatrix(m);
1594}
1595
1596static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1597 intptr_t mask = 1 << shift;
1598 if (pred) {
1599 bits |= mask;
1600 } else {
1601 bits &= ~mask;
1602 }
1603 return bits;
1604}
1605
1606void GrContext::resetStats() {
1607 fGpu->resetStats();
1608}
1609
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001610const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001611 return fGpu->getStats();
1612}
1613
1614void GrContext::printStats() const {
1615 fGpu->printStats();
1616}
1617
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001618GrContext::GrContext(GrGpu* gpu) :
1619 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1620 gpu->supportsStencilWrapOps()) {
1621
bsalomon@google.com27847de2011-02-22 20:59:41 +00001622 fGpu = gpu;
1623 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001624 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001625
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001626 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1627 fGpu->setClipPathRenderer(fCustomPathRenderer);
1628
bsalomon@google.com27847de2011-02-22 20:59:41 +00001629 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1630 MAX_TEXTURE_CACHE_BYTES);
1631 fFontCache = new GrFontCache(fGpu);
1632
1633 fLastDrawCategory = kUnbuffered_DrawCategory;
1634
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001635 fDrawBuffer = NULL;
1636 fDrawBufferVBAllocPool = NULL;
1637 fDrawBufferIBAllocPool = NULL;
1638
bsalomon@google.com205d4602011-04-25 12:43:45 +00001639 fAAFillRectIndexBuffer = NULL;
1640 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001641
1642 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1643 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1644 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1645 }
1646 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001647
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001648 this->setupDrawBuffer();
1649}
1650
1651void GrContext::setupDrawBuffer() {
1652
1653 GrAssert(NULL == fDrawBuffer);
1654 GrAssert(NULL == fDrawBufferVBAllocPool);
1655 GrAssert(NULL == fDrawBufferIBAllocPool);
1656
bsalomon@google.com27847de2011-02-22 20:59:41 +00001657#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001658 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001659 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001660 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1661 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001662 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001663 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001664 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001665 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1666
1667 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1668 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001669#endif
1670
1671#if BATCH_RECT_TO_RECT
1672 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1673#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001674}
1675
bsalomon@google.com27847de2011-02-22 20:59:41 +00001676GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1677 GrDrawTarget* target;
1678#if DEFER_TEXT_RENDERING
1679 target = prepareToDraw(paint, kText_DrawCategory);
1680#else
1681 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1682#endif
1683 SetPaint(paint, target);
1684 return target;
1685}
1686
1687const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1688 return fGpu->getQuadIndexBuffer();
1689}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001690
bsalomon@google.comee435122011-07-01 14:57:55 +00001691GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001692 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001693 if (NULL != fCustomPathRenderer &&
bsalomon@google.comee435122011-07-01 14:57:55 +00001694 fCustomPathRenderer->canDrawPath(path, fill)) {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001695 return fCustomPathRenderer;
1696 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +00001697 GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001698 return &fDefaultPathRenderer;
1699 }
1700}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001701
senorblanco@chromium.org027de5f2011-07-08 18:03:33 +00001702void GrContext::convolveRect(GrTexture* srcTexture,
1703 const SkRect& rect,
1704 float imageIncrement[2],
1705 const float* kernel,
1706 int kernelWidth) {
1707 GrDrawTarget::AutoStateRestore asr(fGpu);
1708 GrMatrix sampleM;
1709 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
1710 GrSamplerState::kClamp_WrapMode,
1711 GrSamplerState::kConvolution_Filter);
1712 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement);
1713 sampleM.setScale(GR_Scalar1 / srcTexture->width(),
1714 GR_Scalar1 / srcTexture->height());
1715 sampler.setMatrix(sampleM);
1716 fGpu->setSamplerState(0, sampler);
1717 fGpu->setViewMatrix(GrMatrix::I());
1718 fGpu->setTexture(0, srcTexture);
1719 fGpu->drawSimpleRect(rect, NULL, 1 << 0);
1720}