blob: d97974a190df80cf8af0e62156ed9bc8cbb2dd00 [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"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000023#include "GrMemory.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000025#include "GrPathUtils.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000026#include "GrTextureCache.h"
27#include "GrTextStrike.h"
28#include SK_USER_TRACE_INCLUDE_FILE
bsalomon@google.com27847de2011-02-22 20:59:41 +000029
bsalomon@google.com91958362011-06-13 17:58:13 +000030// Using MSAA seems to be slower for some yet unknown reason.
31#define PREFER_MSAA_OFFSCREEN_AA 0
32#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000033
bsalomon@google.com27847de2011-02-22 20:59:41 +000034#define DEFER_TEXT_RENDERING 1
35
36#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
37
38static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
39static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
40
41static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
42static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
43
44// We are currently only batching Text and drawRectToRect, both
45// of which use the quad index buffer.
46static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
47static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
48
bsalomon@google.com05ef5102011-05-02 21:14:59 +000049GrContext* GrContext::Create(GrEngine engine,
50 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000051 GrContext* ctx = NULL;
52 GrGpu* fGpu = GrGpu::Create(engine, context3D);
53 if (NULL != fGpu) {
54 ctx = new GrContext(fGpu);
55 fGpu->unref();
56 }
57 return ctx;
58}
59
60GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000061 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000062}
63
64GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000065 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000066 delete fTextureCache;
67 delete fFontCache;
68 delete fDrawBuffer;
69 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000070 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000071 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000072 GrSafeUnref(fAAFillRectIndexBuffer);
73 GrSafeUnref(fAAStrokeRectIndexBuffer);
74 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000075}
76
bsalomon@google.com8fe72472011-03-30 21:26:44 +000077void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000078 contextDestroyed();
79 this->setupDrawBuffer();
80}
81
82void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000083 // abandon first to so destructors
84 // don't try to free the resources in the API.
85 fGpu->abandonResources();
86
bsalomon@google.com8fe72472011-03-30 21:26:44 +000087 delete fDrawBuffer;
88 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000089
bsalomon@google.com8fe72472011-03-30 21:26:44 +000090 delete fDrawBufferVBAllocPool;
91 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000092
bsalomon@google.com8fe72472011-03-30 21:26:44 +000093 delete fDrawBufferIBAllocPool;
94 fDrawBufferIBAllocPool = NULL;
95
bsalomon@google.com205d4602011-04-25 12:43:45 +000096 GrSafeSetNull(fAAFillRectIndexBuffer);
97 GrSafeSetNull(fAAStrokeRectIndexBuffer);
98
bsalomon@google.com8fe72472011-03-30 21:26:44 +000099 fTextureCache->removeAll();
100 fFontCache->freeAll();
101 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000102}
103
104void GrContext::resetContext() {
105 fGpu->markContextDirty();
106}
107
108void GrContext::freeGpuResources() {
109 this->flush();
110 fTextureCache->removeAll();
111 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000112}
113
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000114////////////////////////////////////////////////////////////////////////////////
115
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000116int GrContext::PaintStageVertexLayoutBits(
117 const GrPaint& paint,
118 const bool hasTexCoords[GrPaint::kTotalStages]) {
119 int stageMask = paint.getActiveStageMask();
120 int layout = 0;
121 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
122 if ((1 << i) & stageMask) {
123 if (NULL != hasTexCoords && hasTexCoords[i]) {
124 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
125 } else {
126 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
127 }
128 }
129 }
130 return layout;
131}
132
133
134////////////////////////////////////////////////////////////////////////////////
135
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000136enum {
137 kNPOTBit = 0x1,
138 kFilterBit = 0x2,
139 kKeylessBit = 0x4,
140};
141
142bool GrContext::finalizeTextureKey(GrTextureKey* key,
143 const GrSamplerState& sampler,
144 bool keyless) const {
145 uint32_t bits = 0;
146 uint16_t width = key->width();
147 uint16_t height = key->height();
148
149 if (!fGpu->npotTextureTileSupport()) {
150 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
151
152 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
153 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
154
155 if (tiled && !isPow2) {
156 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000157 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000158 bits |= kFilterBit;
159 }
160 }
161 }
162
163 if (keyless) {
164 bits |= kKeylessBit;
165 }
166 key->finalize(bits);
167 return 0 != bits;
168}
169
bsalomon@google.com27847de2011-02-22 20:59:41 +0000170GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
171 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000172 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000173 return fTextureCache->findAndLock(*key);
174}
175
176static void stretchImage(void* dst,
177 int dstW,
178 int dstH,
179 void* src,
180 int srcW,
181 int srcH,
182 int bpp) {
183 GrFixed dx = (srcW << 16) / dstW;
184 GrFixed dy = (srcH << 16) / dstH;
185
186 GrFixed y = dy >> 1;
187
188 int dstXLimit = dstW*bpp;
189 for (int j = 0; j < dstH; ++j) {
190 GrFixed x = dx >> 1;
191 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
192 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
193 for (int i = 0; i < dstXLimit; i += bpp) {
194 memcpy((uint8_t*) dstRow + i,
195 (uint8_t*) srcRow + (x>>16)*bpp,
196 bpp);
197 x += dx;
198 }
199 y += dy;
200 }
201}
202
203GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
204 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000205 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000206 void* srcData, size_t rowBytes) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +0000207 SK_TRACE_EVENT0("GrContext::createAndLockTexture");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000208 GrAssert(key->width() == desc.fWidth);
209 GrAssert(key->height() == desc.fHeight);
210
211#if GR_DUMP_TEXTURE_UPLOAD
212 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
213#endif
214
215 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000216 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000217 if (special) {
218 GrTextureEntry* clampEntry;
219 GrTextureKey clampKey(*key);
220 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
221
222 if (NULL == clampEntry) {
223 clampEntry = createAndLockTexture(&clampKey,
224 GrSamplerState::ClampNoFilter(),
225 desc, srcData, rowBytes);
226 GrAssert(NULL != clampEntry);
227 if (NULL == clampEntry) {
228 return NULL;
229 }
230 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000231 GrTextureDesc rtDesc = desc;
232 rtDesc.fFlags = rtDesc.fFlags |
233 kRenderTarget_GrTextureFlagBit |
234 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000235 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
236 fGpu->minRenderTargetWidth()));
237 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
238 fGpu->minRenderTargetHeight()));
239
240 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
241
242 if (NULL != texture) {
243 GrDrawTarget::AutoStateRestore asr(fGpu);
244 fGpu->setRenderTarget(texture->asRenderTarget());
245 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000246 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000247 fGpu->setViewMatrix(GrMatrix::I());
248 fGpu->setAlpha(0xff);
249 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
250 fGpu->disableState(GrDrawTarget::kDither_StateBit |
251 GrDrawTarget::kClip_StateBit |
252 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000253 GrSamplerState::Filter filter;
254 // if filtering is not desired then we want to ensure all
255 // texels in the resampled image are copies of texels from
256 // the original.
257 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
258 filter = GrSamplerState::kNearest_Filter;
259 } else {
260 filter = GrSamplerState::kBilinear_Filter;
261 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000262 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
263 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000264 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000265 fGpu->setSamplerState(0, stretchSampler);
266
267 static const GrVertexLayout layout =
268 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
269 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
270
271 if (arg.succeeded()) {
272 GrPoint* verts = (GrPoint*) arg.vertices();
273 verts[0].setIRectFan(0, 0,
274 texture->width(),
275 texture->height(),
276 2*sizeof(GrPoint));
277 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
278 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
279 0, 4);
280 entry = fTextureCache->createAndLock(*key, texture);
281 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000282 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000283 } else {
284 // TODO: Our CPU stretch doesn't filter. But we create separate
285 // stretched textures when the sampler state is either filtered or
286 // not. Either implement filtered stretch blit on CPU or just create
287 // one when FBO case fails.
288
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000289 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000290 // no longer need to clamp at min RT size.
291 rtDesc.fWidth = GrNextPow2(desc.fWidth);
292 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000293 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000294 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
295 rtDesc.fWidth *
296 rtDesc.fHeight);
297 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
298 srcData, desc.fWidth, desc.fHeight, bpp);
299
300 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
301
302 GrTexture* texture = fGpu->createTexture(rtDesc,
303 stretchedPixels.get(),
304 stretchedRowBytes);
305 GrAssert(NULL != texture);
306 entry = fTextureCache->createAndLock(*key, texture);
307 }
308 fTextureCache->unlock(clampEntry);
309
310 } else {
311 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
312 if (NULL != texture) {
313 entry = fTextureCache->createAndLock(*key, texture);
314 } else {
315 entry = NULL;
316 }
317 }
318 return entry;
319}
320
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000321GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000322 uint32_t p0 = desc.fFormat;
323 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
324 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000325 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
326
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000327 GrTextureEntry* entry = fTextureCache->findAndLock(key);
328 if (NULL == entry) {
329 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
330 if (NULL != texture) {
331 entry = fTextureCache->createAndLock(key, texture);
332 }
333 }
334 // If the caller gives us the same desc/sampler twice we don't want
335 // to return the same texture the second time (unless it was previously
336 // released). So we detach the entry from the cache and reattach at release.
337 if (NULL != entry) {
338 fTextureCache->detach(entry);
339 }
340 return entry;
341}
342
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000343GrTextureEntry* GrContext::findApproximateKeylessTexture(
344 const GrTextureDesc& inDesc) {
345 GrTextureDesc desc = inDesc;
346 // bin by pow2 with a reasonable min
347 static const int MIN_SIZE = 256;
348 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
349 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
350
351 uint32_t p0 = desc.fFormat;
352 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
353
354 GrTextureEntry* entry;
355 bool keepTrying = true;
356 int origWidth = desc.fWidth;
357 int origHeight = desc.fHeight;
358 bool doubledW = false;
359 bool doubledH = false;
360
361 do {
362 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
363 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
364 entry = fTextureCache->findAndLock(key);
365
366 // if we miss, relax the fit of the flags...
367 // then try doubling width... then height.
368 if (NULL != entry) {
369 break;
370 }
371 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
372 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
373 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
374 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
375 } else if (!doubledW) {
376 desc.fFlags = inDesc.fFlags;
377 desc.fWidth *= 2;
378 doubledW = true;
379 } else if (!doubledH) {
380 desc.fFlags = inDesc.fFlags;
381 desc.fWidth = origWidth;
382 desc.fHeight *= 2;
383 doubledH = true;
384 } else {
385 break;
386 }
387
388 } while (true);
389
390 if (NULL == entry) {
391 desc.fFlags = inDesc.fFlags;
392 desc.fWidth = origWidth;
393 desc.fHeight = origHeight;
394 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
395 if (NULL != texture) {
396 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
397 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(),
398 true);
399 entry = fTextureCache->createAndLock(key, texture);
400 }
401 }
402
403 // If the caller gives us the same desc/sampler twice we don't want
404 // to return the same texture the second time (unless it was previously
405 // released). So we detach the entry from the cache and reattach at release.
406 if (NULL != entry) {
407 fTextureCache->detach(entry);
408 }
409 return entry;
410}
411
bsalomon@google.com27847de2011-02-22 20:59:41 +0000412void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000413 if (kKeylessBit & entry->key().getPrivateBits()) {
414 fTextureCache->reattachAndUnlock(entry);
415 } else {
416 fTextureCache->unlock(entry);
417 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000418}
419
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000420GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000421 void* srcData,
422 size_t rowBytes) {
423 return fGpu->createTexture(desc, srcData, rowBytes);
424}
425
426void GrContext::getTextureCacheLimits(int* maxTextures,
427 size_t* maxTextureBytes) const {
428 fTextureCache->getLimits(maxTextures, maxTextureBytes);
429}
430
431void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
432 fTextureCache->setLimits(maxTextures, maxTextureBytes);
433}
434
bsalomon@google.com91958362011-06-13 17:58:13 +0000435int GrContext::getMaxTextureSize() const {
436 return fGpu->maxTextureSize();
437}
438
439int GrContext::getMaxRenderTargetSize() const {
440 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000441}
442
443///////////////////////////////////////////////////////////////////////////////
444
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000445GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
446 // validate flags here so that GrGpu subclasses don't have to check
447 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
448 0 != desc.fRenderTargetFlags) {
449 return NULL;
450 }
451 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
452 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
453 return NULL;
454 }
455 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
456 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
457 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
458 return NULL;
459 }
460 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000461}
462
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000463GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000464 return fGpu->createRenderTargetFrom3DApiState();
465}
466
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000467///////////////////////////////////////////////////////////////////////////////
468
bsalomon@google.com27847de2011-02-22 20:59:41 +0000469bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
470 int width, int height) {
471 if (!fGpu->supports8BitPalette()) {
472 return false;
473 }
474
475
476 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
477
478 if (!isPow2) {
479 if (!fGpu->npotTextureSupport()) {
480 return false;
481 }
482
483 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
484 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
485 if (tiled && !fGpu->npotTextureTileSupport()) {
486 return false;
487 }
488 }
489 return true;
490}
491
492////////////////////////////////////////////////////////////////////////////////
493
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000494const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
495
bsalomon@google.com27847de2011-02-22 20:59:41 +0000496void GrContext::setClip(const GrClip& clip) {
497 fGpu->setClip(clip);
498 fGpu->enableState(GrDrawTarget::kClip_StateBit);
499}
500
501void GrContext::setClip(const GrIRect& rect) {
502 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000503 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000504 fGpu->setClip(clip);
505}
506
507////////////////////////////////////////////////////////////////////////////////
508
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000509void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000510 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000511 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000512}
513
514void GrContext::drawPaint(const GrPaint& paint) {
515 // set rect to be big enough to fill the space, but not super-huge, so we
516 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000517 GrRect r;
518 r.setLTRB(0, 0,
519 GrIntToScalar(getRenderTarget()->width()),
520 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000521 GrMatrix inverse;
522 if (fGpu->getViewInverse(&inverse)) {
523 inverse.mapRect(&r);
524 } else {
525 GrPrintf("---- fGpu->getViewInverse failed\n");
526 }
527 this->drawRect(paint, r);
528}
529
bsalomon@google.com205d4602011-04-25 12:43:45 +0000530////////////////////////////////////////////////////////////////////////////////
531
bsalomon@google.com91958362011-06-13 17:58:13 +0000532struct GrContext::OffscreenRecord {
533 OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; }
534 ~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); }
535
536 enum Downsample {
537 k4x4TwoPass_Downsample,
538 k4x4SinglePass_Downsample,
539 kFSAA_Downsample
540 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000541 int fTileSizeX;
542 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000543 int fTileCountX;
544 int fTileCountY;
545 int fScale;
546 GrTextureEntry* fEntry0;
547 GrTextureEntry* fEntry1;
548 GrDrawTarget::SavedDrawState fSavedState;
549};
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
bsalomon@google.com91958362011-06-13 17:58:13 +0000662 target->saveCurrentDrawState(&record->fSavedState);
663 return true;
664}
665
666void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
667 const GrIRect& boundRect,
668 int tileX, int tileY,
669 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000670
671 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
672 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000673
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000674 GrPaint tempPaint;
675 tempPaint.reset();
676 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000677 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000678
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000679 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000680 int left = boundRect.fLeft + tileX * record->fTileSizeX;
681 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000682 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000683 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000684 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000685 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000686 target->postConcatViewMatrix(scaleM);
687
688 // clip gets applied in second pass
689 target->disableState(GrDrawTarget::kClip_StateBit);
690
bsalomon@google.com91958362011-06-13 17:58:13 +0000691 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000692 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000693 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000694 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000695 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
696 record->fScale * h);
697#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.com91958362011-06-13 17:58:13 +0000719
720 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);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000783
784 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000785 GrMatrix invVM;
786 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000787 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000788 }
789 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000790 // This is important when tiling, otherwise second tile's
791 // pass 1 view matrix will be incorrect.
792 GrDrawTarget::AutoViewMatrixRestore avmr(target);
793
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000794 target->setViewMatrix(GrMatrix::I());
795
796 target->setTexture(kOffscreenStage, src);
797 sampleM.setScale(scale * GR_Scalar1 / src->width(),
798 scale * GR_Scalar1 / src->height());
799 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000800 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000801 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000802 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000803
reed@google.com20efde72011-05-09 17:00:02 +0000804 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000805 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000806 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000807 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000808}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000809
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000810void GrContext::cleanupOffscreenAA(GrDrawTarget* target,
811 GrPathRenderer* pr,
812 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000813 this->unlockTexture(record->fEntry0);
814 record->fEntry0 = NULL;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +0000815 if (pr) {
816 // Counterpart of scale() in prepareForOffscreenAA()
817 //pr->scaleCurveTolerance(SkScalarInvert(SkIntToScalar(record->fScale)));
818 }
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000819 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000820 this->unlockTexture(record->fEntry1);
821 record->fEntry1 = NULL;
822 }
823 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000824}
825
826////////////////////////////////////////////////////////////////////////////////
827
bsalomon@google.com27847de2011-02-22 20:59:41 +0000828/* create a triangle strip that strokes the specified triangle. There are 8
829 unique vertices, but we repreat the last 2 to close up. Alternatively we
830 could use an indices array, and then only send 8 verts, but not sure that
831 would be faster.
832 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000833static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000834 GrScalar width) {
835 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000836 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000837
838 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
839 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
840 verts[2].set(rect.fRight - rad, rect.fTop + rad);
841 verts[3].set(rect.fRight + rad, rect.fTop - rad);
842 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
843 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
844 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
845 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
846 verts[8] = verts[0];
847 verts[9] = verts[1];
848}
849
bsalomon@google.com205d4602011-04-25 12:43:45 +0000850static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000851 // FIXME: This was copied from SkGpuDevice, seems like
852 // we should have already smeared a in caller if that
853 // is what is desired.
854 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000855 unsigned a = GrColorUnpackA(paint.fColor);
856 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000857 } else {
858 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000859 }
860}
861
862static void setInsetFan(GrPoint* pts, size_t stride,
863 const GrRect& r, GrScalar dx, GrScalar dy) {
864 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
865}
866
867static const uint16_t gFillAARectIdx[] = {
868 0, 1, 5, 5, 4, 0,
869 1, 2, 6, 6, 5, 1,
870 2, 3, 7, 7, 6, 2,
871 3, 0, 4, 4, 7, 3,
872 4, 5, 6, 6, 7, 4,
873};
874
875int GrContext::aaFillRectIndexCount() const {
876 return GR_ARRAY_COUNT(gFillAARectIdx);
877}
878
879GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
880 if (NULL == fAAFillRectIndexBuffer) {
881 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
882 false);
883 GrAssert(NULL != fAAFillRectIndexBuffer);
884#if GR_DEBUG
885 bool updated =
886#endif
887 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
888 sizeof(gFillAARectIdx));
889 GR_DEBUGASSERT(updated);
890 }
891 return fAAFillRectIndexBuffer;
892}
893
894static const uint16_t gStrokeAARectIdx[] = {
895 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
896 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
897 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
898 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
899
900 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
901 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
902 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
903 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
904
905 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
906 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
907 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
908 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
909};
910
911int GrContext::aaStrokeRectIndexCount() const {
912 return GR_ARRAY_COUNT(gStrokeAARectIdx);
913}
914
915GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
916 if (NULL == fAAStrokeRectIndexBuffer) {
917 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
918 false);
919 GrAssert(NULL != fAAStrokeRectIndexBuffer);
920#if GR_DEBUG
921 bool updated =
922#endif
923 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
924 sizeof(gStrokeAARectIdx));
925 GR_DEBUGASSERT(updated);
926 }
927 return fAAStrokeRectIndexBuffer;
928}
929
930void GrContext::fillAARect(GrDrawTarget* target,
931 const GrPaint& paint,
932 const GrRect& devRect) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000933 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
934 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000935
936 size_t vsize = GrDrawTarget::VertexSize(layout);
937
938 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
939
940 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
941
942 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
943 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
944
945 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
946 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
947
948 verts += sizeof(GrPoint);
949 for (int i = 0; i < 4; ++i) {
950 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
951 }
952
953 GrColor innerColor = getColorForMesh(paint);
954 verts += 4 * vsize;
955 for (int i = 0; i < 4; ++i) {
956 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
957 }
958
959 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
960
961 target->drawIndexed(kTriangles_PrimitiveType, 0,
962 0, 8, this->aaFillRectIndexCount());
963}
964
965void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
966 const GrRect& devRect, const GrVec& devStrokeSize) {
967 const GrScalar& dx = devStrokeSize.fX;
968 const GrScalar& dy = devStrokeSize.fY;
969 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
970 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
971
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000972 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
973 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000974
975 GrScalar spare;
976 {
977 GrScalar w = devRect.width() - dx;
978 GrScalar h = devRect.height() - dy;
979 spare = GrMin(w, h);
980 }
981
982 if (spare <= 0) {
983 GrRect r(devRect);
984 r.inset(-rx, -ry);
985 fillAARect(target, paint, r);
986 return;
987 }
988
989 size_t vsize = GrDrawTarget::VertexSize(layout);
990
991 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
992
993 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
994
995 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
996 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
997 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
998 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
999
1000 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
1001 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
1002 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
1003 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
1004
1005 verts += sizeof(GrPoint);
1006 for (int i = 0; i < 4; ++i) {
1007 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1008 }
1009
1010 GrColor innerColor = getColorForMesh(paint);
1011 verts += 4 * vsize;
1012 for (int i = 0; i < 8; ++i) {
1013 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1014 }
1015
1016 verts += 8 * vsize;
1017 for (int i = 0; i < 8; ++i) {
1018 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1019 }
1020
1021 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1022 target->drawIndexed(kTriangles_PrimitiveType,
1023 0, 0, 16, aaStrokeRectIndexCount());
1024}
1025
reed@google.com20efde72011-05-09 17:00:02 +00001026/**
1027 * Returns true if the rects edges are integer-aligned.
1028 */
1029static bool isIRect(const GrRect& r) {
1030 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1031 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1032}
1033
bsalomon@google.com205d4602011-04-25 12:43:45 +00001034static bool apply_aa_to_rect(GrDrawTarget* target,
1035 GrGpu* gpu,
1036 const GrPaint& paint,
1037 const GrRect& rect,
1038 GrScalar width,
1039 const GrMatrix* matrix,
1040 GrMatrix* combinedMatrix,
1041 GrRect* devRect) {
1042 // we use a simple alpha ramp to do aa on axis-aligned rects
1043 // do AA with alpha ramp if the caller requested AA, the rect
1044 // will be axis-aligned,the render target is not
1045 // multisampled, and the rect won't land on integer coords.
1046
1047 if (!paint.fAntiAlias) {
1048 return false;
1049 }
1050
1051 if (target->getRenderTarget()->isMultisampled()) {
1052 return false;
1053 }
1054
1055 if (0 == width && gpu->supportsAALines()) {
1056 return false;
1057 }
1058
1059 if (!target->getViewMatrix().preservesAxisAlignment()) {
1060 return false;
1061 }
1062
1063 if (NULL != matrix &&
1064 !matrix->preservesAxisAlignment()) {
1065 return false;
1066 }
1067
1068 *combinedMatrix = target->getViewMatrix();
1069 if (NULL != matrix) {
1070 combinedMatrix->preConcat(*matrix);
1071 GrAssert(combinedMatrix->preservesAxisAlignment());
1072 }
1073
1074 combinedMatrix->mapRect(devRect, rect);
1075 devRect->sort();
1076
1077 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001078 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001079 } else {
1080 return true;
1081 }
1082}
1083
bsalomon@google.com27847de2011-02-22 20:59:41 +00001084void GrContext::drawRect(const GrPaint& paint,
1085 const GrRect& rect,
1086 GrScalar width,
1087 const GrMatrix* matrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001088 SK_TRACE_EVENT0("GrContext::drawRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001089
1090 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001091 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001092
bsalomon@google.com205d4602011-04-25 12:43:45 +00001093 GrRect devRect = rect;
1094 GrMatrix combinedMatrix;
1095 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1096 &combinedMatrix, &devRect);
1097
1098 if (doAA) {
1099 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001100 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001101 GrMatrix inv;
1102 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001103 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001104 }
1105 }
1106 target->setViewMatrix(GrMatrix::I());
1107 if (width >= 0) {
1108 GrVec strokeSize;;
1109 if (width > 0) {
1110 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001111 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001112 strokeSize.setAbs(strokeSize);
1113 } else {
1114 strokeSize.set(GR_Scalar1, GR_Scalar1);
1115 }
1116 strokeAARect(target, paint, devRect, strokeSize);
1117 } else {
1118 fillAARect(target, paint, devRect);
1119 }
1120 return;
1121 }
1122
bsalomon@google.com27847de2011-02-22 20:59:41 +00001123 if (width >= 0) {
1124 // TODO: consider making static vertex buffers for these cases.
1125 // Hairline could be done by just adding closing vertex to
1126 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001127 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1128
bsalomon@google.com27847de2011-02-22 20:59:41 +00001129 static const int worstCaseVertCount = 10;
1130 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1131
1132 if (!geo.succeeded()) {
1133 return;
1134 }
1135
1136 GrPrimitiveType primType;
1137 int vertCount;
1138 GrPoint* vertex = geo.positions();
1139
1140 if (width > 0) {
1141 vertCount = 10;
1142 primType = kTriangleStrip_PrimitiveType;
1143 setStrokeRectStrip(vertex, rect, width);
1144 } else {
1145 // hairline
1146 vertCount = 5;
1147 primType = kLineStrip_PrimitiveType;
1148 vertex[0].set(rect.fLeft, rect.fTop);
1149 vertex[1].set(rect.fRight, rect.fTop);
1150 vertex[2].set(rect.fRight, rect.fBottom);
1151 vertex[3].set(rect.fLeft, rect.fBottom);
1152 vertex[4].set(rect.fLeft, rect.fTop);
1153 }
1154
1155 GrDrawTarget::AutoViewMatrixRestore avmr;
1156 if (NULL != matrix) {
1157 avmr.set(target);
1158 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001159 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001160 }
1161
1162 target->drawNonIndexed(primType, 0, vertCount);
1163 } else {
1164 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001165 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1166
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001167 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001168 fGpu->getUnitSquareVertexBuffer());
1169 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1170 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001171 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001172 0, rect.height(), rect.fTop,
1173 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001174
1175 if (NULL != matrix) {
1176 m.postConcat(*matrix);
1177 }
1178
1179 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001180 target->preConcatSamplerMatrices(stageMask, m);
1181
bsalomon@google.com27847de2011-02-22 20:59:41 +00001182 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1183 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001184 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001185 #endif
1186 }
1187}
1188
1189void GrContext::drawRectToRect(const GrPaint& paint,
1190 const GrRect& dstRect,
1191 const GrRect& srcRect,
1192 const GrMatrix* dstMatrix,
1193 const GrMatrix* srcMatrix) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001194 SK_TRACE_EVENT0("GrContext::drawRectToRect");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001195
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001196 // srcRect refers to paint's first texture
1197 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001198 drawRect(paint, dstRect, -1, dstMatrix);
1199 return;
1200 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001201
bsalomon@google.com27847de2011-02-22 20:59:41 +00001202 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1203
1204#if GR_STATIC_RECT_VB
1205 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001206
1207 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001208 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1209
1210 GrMatrix m;
1211
1212 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1213 0, dstRect.height(), dstRect.fTop,
1214 0, 0, GrMatrix::I()[8]);
1215 if (NULL != dstMatrix) {
1216 m.postConcat(*dstMatrix);
1217 }
1218 target->preConcatViewMatrix(m);
1219
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001220 // srcRect refers to first stage
1221 int otherStageMask = paint.getActiveStageMask() &
1222 (~(1 << GrPaint::kFirstTextureStage));
1223 if (otherStageMask) {
1224 target->preConcatSamplerMatrices(otherStageMask, m);
1225 }
1226
bsalomon@google.com27847de2011-02-22 20:59:41 +00001227 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1228 0, srcRect.height(), srcRect.fTop,
1229 0, 0, GrMatrix::I()[8]);
1230 if (NULL != srcMatrix) {
1231 m.postConcat(*srcMatrix);
1232 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001233 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001234
1235 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1236 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1237#else
1238
1239 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001240#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001241 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001242#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001243 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1244#endif
1245
1246 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1247 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1248 srcRects[0] = &srcRect;
1249 srcMatrices[0] = srcMatrix;
1250
1251 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1252#endif
1253}
1254
1255void GrContext::drawVertices(const GrPaint& paint,
1256 GrPrimitiveType primitiveType,
1257 int vertexCount,
1258 const GrPoint positions[],
1259 const GrPoint texCoords[],
1260 const GrColor colors[],
1261 const uint16_t indices[],
1262 int indexCount) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001263 SK_TRACE_EVENT0("GrContext::drawVertices");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001264
1265 GrDrawTarget::AutoReleaseGeometry geo;
1266
1267 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1268
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001269 bool hasTexCoords[GrPaint::kTotalStages] = {
1270 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1271 0 // remaining stages use positions
1272 };
1273
1274 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001275
1276 if (NULL != colors) {
1277 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001278 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001279 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001280
1281 if (sizeof(GrPoint) != vertexSize) {
1282 if (!geo.set(target, layout, vertexCount, 0)) {
1283 GrPrintf("Failed to get space for vertices!");
1284 return;
1285 }
1286 int texOffsets[GrDrawTarget::kMaxTexCoords];
1287 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001288 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1289 texOffsets,
1290 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001291 void* curVertex = geo.vertices();
1292
1293 for (int i = 0; i < vertexCount; ++i) {
1294 *((GrPoint*)curVertex) = positions[i];
1295
1296 if (texOffsets[0] > 0) {
1297 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1298 }
1299 if (colorOffset > 0) {
1300 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1301 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001302 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001303 }
1304 } else {
1305 target->setVertexSourceToArray(layout, positions, vertexCount);
1306 }
1307
bsalomon@google.com91958362011-06-13 17:58:13 +00001308 // we don't currently apply offscreen AA to this path. Need improved
1309 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001310
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001311 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001312 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001313 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001314 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001315 target->drawNonIndexed(primitiveType, 0, vertexCount);
1316 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001317}
1318
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001319///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001320
reed@google.com07f3ee12011-05-16 17:21:57 +00001321void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1322 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001323
bsalomon@google.com27847de2011-02-22 20:59:41 +00001324 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001325 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001326
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001327 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001328 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001329
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001330 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001331
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001332 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001333 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1334 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001335 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001336 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001337 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001338 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001339 return;
1340 }
1341 }
reed@google.com70c136e2011-06-03 19:51:26 +00001342
reed@google.com07f3ee12011-05-16 17:21:57 +00001343 GrRect pathBounds = path.getBounds();
1344 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001345 if (NULL != translate) {
1346 pathBounds.offset(*translate);
1347 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001348 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001349 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001350 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001351 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001352 return;
1353 }
1354 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001355 OffscreenRecord record;
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001356 if (this->prepareForOffscreenAA(target, needsStencil, bound,
1357 pr, &record)) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001358 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1359 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1360 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
1361 pr->drawPath(target, 0, path, fill, translate);
1362 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1363 }
1364 }
tomhudson@google.comd22b6e42011-06-24 15:53:40 +00001365 this->cleanupOffscreenAA(target, pr, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001366 if (IsFillInverted(fill) && bound != clipIBounds) {
1367 int stageMask = paint.getActiveStageMask();
1368 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 }
reed@google.com70c136e2011-06-03 19:51:26 +00001393 }
1394
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001395 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001396
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001397 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001398}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001399
bsalomon@google.com27847de2011-02-22 20:59:41 +00001400////////////////////////////////////////////////////////////////////////////////
1401
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001402void GrContext::flush(int flagsBitfield) {
1403 if (kDiscard_FlushBit & flagsBitfield) {
1404 fDrawBuffer->reset();
1405 } else {
1406 flushDrawBuffer();
1407 }
1408
1409 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001410 fGpu->forceRenderTargetFlush();
1411 }
1412}
1413
1414void GrContext::flushText() {
1415 if (kText_DrawCategory == fLastDrawCategory) {
1416 flushDrawBuffer();
1417 }
1418}
1419
1420void GrContext::flushDrawBuffer() {
1421#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001422 if (fDrawBuffer) {
1423 fDrawBuffer->playback(fGpu);
1424 fDrawBuffer->reset();
1425 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001426#endif
1427}
1428
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001429bool GrContext::readTexturePixels(GrTexture* texture,
1430 int left, int top, int width, int height,
1431 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001432 SK_TRACE_EVENT0("GrContext::readTexturePixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001433
1434 // TODO: code read pixels for textures that aren't rendertargets
1435
1436 this->flush();
1437 GrRenderTarget* target = texture->asRenderTarget();
1438 if (NULL != target) {
1439 return fGpu->readPixels(target,
1440 left, top, width, height,
1441 config, buffer);
1442 } else {
1443 return false;
1444 }
1445}
1446
1447bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1448 int left, int top, int width, int height,
1449 GrPixelConfig config, void* buffer) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001450 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001451 uint32_t flushFlags = 0;
1452 if (NULL == target) {
1453 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1454 }
1455
1456 this->flush(flushFlags);
1457 return fGpu->readPixels(target,
1458 left, top, width, height,
1459 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001460}
1461
1462void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001463 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001464 size_t stride) {
tomhudson@google.com278cbb42011-06-30 19:37:01 +00001465 SK_TRACE_EVENT0("GrContext::writePixels");
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466
1467 // TODO: when underlying api has a direct way to do this we should use it
1468 // (e.g. glDrawPixels on desktop GL).
1469
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001470 const GrTextureDesc desc = {
1471 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472 };
1473 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1474 if (NULL == texture) {
1475 return;
1476 }
1477
1478 this->flush(true);
1479
1480 GrAutoUnref aur(texture);
1481 GrDrawTarget::AutoStateRestore asr(fGpu);
1482
1483 GrMatrix matrix;
1484 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1485 fGpu->setViewMatrix(matrix);
1486
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001487 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001488 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1489 fGpu->setAlpha(0xFF);
1490 fGpu->setBlendFunc(kOne_BlendCoeff,
1491 kZero_BlendCoeff);
1492 fGpu->setTexture(0, texture);
1493
1494 GrSamplerState sampler;
1495 sampler.setClampNoFilter();
1496 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1497 sampler.setMatrix(matrix);
1498 fGpu->setSamplerState(0, sampler);
1499
1500 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1501 static const int VCOUNT = 4;
1502
1503 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1504 if (!geo.succeeded()) {
1505 return;
1506 }
1507 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1508 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1509}
1510////////////////////////////////////////////////////////////////////////////////
1511
1512void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001513
1514 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1515 int s = i + GrPaint::kFirstTextureStage;
1516 target->setTexture(s, paint.getTexture(i));
1517 target->setSamplerState(s, *paint.getTextureSampler(i));
1518 }
1519
1520 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1521
1522 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1523 int s = i + GrPaint::kFirstMaskStage;
1524 target->setTexture(s, paint.getMask(i));
1525 target->setSamplerState(s, *paint.getMaskSampler(i));
1526 }
1527
bsalomon@google.com27847de2011-02-22 20:59:41 +00001528 target->setColor(paint.fColor);
1529
1530 if (paint.fDither) {
1531 target->enableState(GrDrawTarget::kDither_StateBit);
1532 } else {
1533 target->disableState(GrDrawTarget::kDither_StateBit);
1534 }
1535 if (paint.fAntiAlias) {
1536 target->enableState(GrDrawTarget::kAntialias_StateBit);
1537 } else {
1538 target->disableState(GrDrawTarget::kAntialias_StateBit);
1539 }
1540 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001541 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001542}
1543
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001544GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001545 DrawCategory category) {
1546 if (category != fLastDrawCategory) {
1547 flushDrawBuffer();
1548 fLastDrawCategory = category;
1549 }
1550 SetPaint(paint, fGpu);
1551 GrDrawTarget* target = fGpu;
1552 switch (category) {
1553 case kText_DrawCategory:
1554#if DEFER_TEXT_RENDERING
1555 target = fDrawBuffer;
1556 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1557#else
1558 target = fGpu;
1559#endif
1560 break;
1561 case kUnbuffered_DrawCategory:
1562 target = fGpu;
1563 break;
1564 case kBuffered_DrawCategory:
1565 target = fDrawBuffer;
1566 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1567 break;
1568 }
1569 return target;
1570}
1571
1572////////////////////////////////////////////////////////////////////////////////
1573
bsalomon@google.com27847de2011-02-22 20:59:41 +00001574void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001575 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001576 fGpu->setRenderTarget(target);
1577}
1578
1579GrRenderTarget* GrContext::getRenderTarget() {
1580 return fGpu->getRenderTarget();
1581}
1582
1583const GrRenderTarget* GrContext::getRenderTarget() const {
1584 return fGpu->getRenderTarget();
1585}
1586
1587const GrMatrix& GrContext::getMatrix() const {
1588 return fGpu->getViewMatrix();
1589}
1590
1591void GrContext::setMatrix(const GrMatrix& m) {
1592 fGpu->setViewMatrix(m);
1593}
1594
1595void GrContext::concatMatrix(const GrMatrix& m) const {
1596 fGpu->preConcatViewMatrix(m);
1597}
1598
1599static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1600 intptr_t mask = 1 << shift;
1601 if (pred) {
1602 bits |= mask;
1603 } else {
1604 bits &= ~mask;
1605 }
1606 return bits;
1607}
1608
1609void GrContext::resetStats() {
1610 fGpu->resetStats();
1611}
1612
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001613const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001614 return fGpu->getStats();
1615}
1616
1617void GrContext::printStats() const {
1618 fGpu->printStats();
1619}
1620
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001621GrContext::GrContext(GrGpu* gpu) :
1622 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1623 gpu->supportsStencilWrapOps()) {
1624
bsalomon@google.com27847de2011-02-22 20:59:41 +00001625 fGpu = gpu;
1626 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001627 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001628
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001629 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1630 fGpu->setClipPathRenderer(fCustomPathRenderer);
1631
bsalomon@google.com27847de2011-02-22 20:59:41 +00001632 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1633 MAX_TEXTURE_CACHE_BYTES);
1634 fFontCache = new GrFontCache(fGpu);
1635
1636 fLastDrawCategory = kUnbuffered_DrawCategory;
1637
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001638 fDrawBuffer = NULL;
1639 fDrawBufferVBAllocPool = NULL;
1640 fDrawBufferIBAllocPool = NULL;
1641
bsalomon@google.com205d4602011-04-25 12:43:45 +00001642 fAAFillRectIndexBuffer = NULL;
1643 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001644
1645 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1646 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1647 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1648 }
1649 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001650
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001651 this->setupDrawBuffer();
1652}
1653
1654void GrContext::setupDrawBuffer() {
1655
1656 GrAssert(NULL == fDrawBuffer);
1657 GrAssert(NULL == fDrawBufferVBAllocPool);
1658 GrAssert(NULL == fDrawBufferIBAllocPool);
1659
bsalomon@google.com27847de2011-02-22 20:59:41 +00001660#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001661 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001662 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001663 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1664 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001665 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001666 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001667 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001668 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1669
1670 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1671 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001672#endif
1673
1674#if BATCH_RECT_TO_RECT
1675 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1676#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001677}
1678
bsalomon@google.com27847de2011-02-22 20:59:41 +00001679GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1680 GrDrawTarget* target;
1681#if DEFER_TEXT_RENDERING
1682 target = prepareToDraw(paint, kText_DrawCategory);
1683#else
1684 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1685#endif
1686 SetPaint(paint, target);
1687 return target;
1688}
1689
1690const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1691 return fGpu->getQuadIndexBuffer();
1692}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001693
1694GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001695 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.comdfe75bc2011-03-25 12:31:16 +00001698 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1699 return fCustomPathRenderer;
1700 } else {
1701 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1702 return &fDefaultPathRenderer;
1703 }
1704}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001705