blob: 56ebb68c686820bebb774e08366d6a484633c3b2 [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
17#include "GrContext.h"
bsalomon@google.com05ef5102011-05-02 21:14:59 +000018#include "GrGpu.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000019#include "GrTextureCache.h"
20#include "GrTextStrike.h"
21#include "GrMemory.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000022#include "GrClipIterator.h"
23#include "GrIndexBuffer.h"
24#include "GrInOrderDrawBuffer.h"
25#include "GrBufferAllocPool.h"
26#include "GrPathRenderer.h"
27
bsalomon@google.com91958362011-06-13 17:58:13 +000028// Using MSAA seems to be slower for some yet unknown reason.
29#define PREFER_MSAA_OFFSCREEN_AA 0
30#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4
bsalomon@google.com06afe7b2011-04-26 15:31:40 +000031
bsalomon@google.com27847de2011-02-22 20:59:41 +000032#define DEFER_TEXT_RENDERING 1
33
34#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
35
36static const size_t MAX_TEXTURE_CACHE_COUNT = 128;
37static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024;
38
39static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18;
40static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
41
42// We are currently only batching Text and drawRectToRect, both
43// of which use the quad index buffer.
44static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0;
45static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0;
46
bsalomon@google.com05ef5102011-05-02 21:14:59 +000047GrContext* GrContext::Create(GrEngine engine,
48 GrPlatform3DContext context3D) {
bsalomon@google.com27847de2011-02-22 20:59:41 +000049 GrContext* ctx = NULL;
50 GrGpu* fGpu = GrGpu::Create(engine, context3D);
51 if (NULL != fGpu) {
52 ctx = new GrContext(fGpu);
53 fGpu->unref();
54 }
55 return ctx;
56}
57
58GrContext* GrContext::CreateGLShaderContext() {
thakis@chromium.org7e12f822011-06-07 22:18:07 +000059 return GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
bsalomon@google.com27847de2011-02-22 20:59:41 +000060}
61
62GrContext::~GrContext() {
bsalomon@google.com8fe72472011-03-30 21:26:44 +000063 this->flush();
bsalomon@google.com27847de2011-02-22 20:59:41 +000064 delete fTextureCache;
65 delete fFontCache;
66 delete fDrawBuffer;
67 delete fDrawBufferVBAllocPool;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +000068 delete fDrawBufferIBAllocPool;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000069 GrSafeUnref(fCustomPathRenderer);
bsalomon@google.com205d4602011-04-25 12:43:45 +000070 GrSafeUnref(fAAFillRectIndexBuffer);
71 GrSafeUnref(fAAStrokeRectIndexBuffer);
72 fGpu->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +000073}
74
bsalomon@google.com8fe72472011-03-30 21:26:44 +000075void GrContext::contextLost() {
junov@google.com53a55842011-06-08 22:55:10 +000076 contextDestroyed();
77 this->setupDrawBuffer();
78}
79
80void GrContext::contextDestroyed() {
bsalomon@google.com205d4602011-04-25 12:43:45 +000081 // abandon first to so destructors
82 // don't try to free the resources in the API.
83 fGpu->abandonResources();
84
bsalomon@google.com8fe72472011-03-30 21:26:44 +000085 delete fDrawBuffer;
86 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000087
bsalomon@google.com8fe72472011-03-30 21:26:44 +000088 delete fDrawBufferVBAllocPool;
89 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +000090
bsalomon@google.com8fe72472011-03-30 21:26:44 +000091 delete fDrawBufferIBAllocPool;
92 fDrawBufferIBAllocPool = NULL;
93
bsalomon@google.com205d4602011-04-25 12:43:45 +000094 GrSafeSetNull(fAAFillRectIndexBuffer);
95 GrSafeSetNull(fAAStrokeRectIndexBuffer);
96
bsalomon@google.com8fe72472011-03-30 21:26:44 +000097 fTextureCache->removeAll();
98 fFontCache->freeAll();
99 fGpu->markContextDirty();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000100}
101
102void GrContext::resetContext() {
103 fGpu->markContextDirty();
104}
105
106void GrContext::freeGpuResources() {
107 this->flush();
108 fTextureCache->removeAll();
109 fFontCache->freeAll();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000110}
111
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000112////////////////////////////////////////////////////////////////////////////////
113
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000114int GrContext::PaintStageVertexLayoutBits(
115 const GrPaint& paint,
116 const bool hasTexCoords[GrPaint::kTotalStages]) {
117 int stageMask = paint.getActiveStageMask();
118 int layout = 0;
119 for (int i = 0; i < GrPaint::kTotalStages; ++i) {
120 if ((1 << i) & stageMask) {
121 if (NULL != hasTexCoords && hasTexCoords[i]) {
122 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i);
123 } else {
124 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i);
125 }
126 }
127 }
128 return layout;
129}
130
131
132////////////////////////////////////////////////////////////////////////////////
133
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000134enum {
135 kNPOTBit = 0x1,
136 kFilterBit = 0x2,
137 kKeylessBit = 0x4,
138};
139
140bool GrContext::finalizeTextureKey(GrTextureKey* key,
141 const GrSamplerState& sampler,
142 bool keyless) const {
143 uint32_t bits = 0;
144 uint16_t width = key->width();
145 uint16_t height = key->height();
146
147 if (!fGpu->npotTextureTileSupport()) {
148 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
149
150 bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) ||
151 (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode);
152
153 if (tiled && !isPow2) {
154 bits |= kNPOTBit;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000155 if (GrSamplerState::kNearest_Filter != sampler.getFilter()) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000156 bits |= kFilterBit;
157 }
158 }
159 }
160
161 if (keyless) {
162 bits |= kKeylessBit;
163 }
164 key->finalize(bits);
165 return 0 != bits;
166}
167
bsalomon@google.com27847de2011-02-22 20:59:41 +0000168GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key,
169 const GrSamplerState& sampler) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000170 finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000171 return fTextureCache->findAndLock(*key);
172}
173
174static void stretchImage(void* dst,
175 int dstW,
176 int dstH,
177 void* src,
178 int srcW,
179 int srcH,
180 int bpp) {
181 GrFixed dx = (srcW << 16) / dstW;
182 GrFixed dy = (srcH << 16) / dstH;
183
184 GrFixed y = dy >> 1;
185
186 int dstXLimit = dstW*bpp;
187 for (int j = 0; j < dstH; ++j) {
188 GrFixed x = dx >> 1;
189 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp;
190 void* dstRow = (uint8_t*)dst + j*dstW*bpp;
191 for (int i = 0; i < dstXLimit; i += bpp) {
192 memcpy((uint8_t*) dstRow + i,
193 (uint8_t*) srcRow + (x>>16)*bpp,
194 bpp);
195 x += dx;
196 }
197 y += dy;
198 }
199}
200
201GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
202 const GrSamplerState& sampler,
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000203 const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000204 void* srcData, size_t rowBytes) {
205 GrAssert(key->width() == desc.fWidth);
206 GrAssert(key->height() == desc.fHeight);
207
208#if GR_DUMP_TEXTURE_UPLOAD
209 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight);
210#endif
211
212 GrTextureEntry* entry = NULL;
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000213 bool special = finalizeTextureKey(key, sampler, false);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000214 if (special) {
215 GrTextureEntry* clampEntry;
216 GrTextureKey clampKey(*key);
217 clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter());
218
219 if (NULL == clampEntry) {
220 clampEntry = createAndLockTexture(&clampKey,
221 GrSamplerState::ClampNoFilter(),
222 desc, srcData, rowBytes);
223 GrAssert(NULL != clampEntry);
224 if (NULL == clampEntry) {
225 return NULL;
226 }
227 }
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000228 GrTextureDesc rtDesc = desc;
229 rtDesc.fFlags = rtDesc.fFlags |
230 kRenderTarget_GrTextureFlagBit |
231 kNoStencil_GrTextureFlagBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000232 rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth,
233 fGpu->minRenderTargetWidth()));
234 rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight,
235 fGpu->minRenderTargetHeight()));
236
237 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
238
239 if (NULL != texture) {
240 GrDrawTarget::AutoStateRestore asr(fGpu);
241 fGpu->setRenderTarget(texture->asRenderTarget());
242 fGpu->setTexture(0, clampEntry->texture());
bsalomon@google.comd302f142011-03-03 13:54:13 +0000243 fGpu->disableStencil();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000244 fGpu->setViewMatrix(GrMatrix::I());
245 fGpu->setAlpha(0xff);
246 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
247 fGpu->disableState(GrDrawTarget::kDither_StateBit |
248 GrDrawTarget::kClip_StateBit |
249 GrDrawTarget::kAntialias_StateBit);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000250 GrSamplerState::Filter filter;
251 // if filtering is not desired then we want to ensure all
252 // texels in the resampled image are copies of texels from
253 // the original.
254 if (GrSamplerState::kNearest_Filter == sampler.getFilter()) {
255 filter = GrSamplerState::kNearest_Filter;
256 } else {
257 filter = GrSamplerState::kBilinear_Filter;
258 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000259 GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode,
260 GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000261 filter);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000262 fGpu->setSamplerState(0, stretchSampler);
263
264 static const GrVertexLayout layout =
265 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0);
266 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0);
267
268 if (arg.succeeded()) {
269 GrPoint* verts = (GrPoint*) arg.vertices();
270 verts[0].setIRectFan(0, 0,
271 texture->width(),
272 texture->height(),
273 2*sizeof(GrPoint));
274 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint));
275 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType,
276 0, 4);
277 entry = fTextureCache->createAndLock(*key, texture);
278 }
bsalomon@google.com1da07462011-03-10 14:51:57 +0000279 texture->releaseRenderTarget();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000280 } else {
281 // TODO: Our CPU stretch doesn't filter. But we create separate
282 // stretched textures when the sampler state is either filtered or
283 // not. Either implement filtered stretch blit on CPU or just create
284 // one when FBO case fails.
285
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000286 rtDesc.fFlags = kNone_GrTextureFlags;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000287 // no longer need to clamp at min RT size.
288 rtDesc.fWidth = GrNextPow2(desc.fWidth);
289 rtDesc.fHeight = GrNextPow2(desc.fHeight);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000290 int bpp = GrBytesPerPixel(desc.fFormat);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000291 GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
292 rtDesc.fWidth *
293 rtDesc.fHeight);
294 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight,
295 srcData, desc.fWidth, desc.fHeight, bpp);
296
297 size_t stretchedRowBytes = rtDesc.fWidth * bpp;
298
299 GrTexture* texture = fGpu->createTexture(rtDesc,
300 stretchedPixels.get(),
301 stretchedRowBytes);
302 GrAssert(NULL != texture);
303 entry = fTextureCache->createAndLock(*key, texture);
304 }
305 fTextureCache->unlock(clampEntry);
306
307 } else {
308 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes);
309 if (NULL != texture) {
310 entry = fTextureCache->createAndLock(*key, texture);
311 } else {
312 entry = NULL;
313 }
314 }
315 return entry;
316}
317
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000318GrTextureEntry* GrContext::lockKeylessTexture(const GrTextureDesc& desc) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000319 uint32_t p0 = desc.fFormat;
320 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
321 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
bsalomon@google.coma39f4042011-04-26 13:18:16 +0000322 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
323
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000324 GrTextureEntry* entry = fTextureCache->findAndLock(key);
325 if (NULL == entry) {
326 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
327 if (NULL != texture) {
328 entry = fTextureCache->createAndLock(key, texture);
329 }
330 }
331 // If the caller gives us the same desc/sampler twice we don't want
332 // to return the same texture the second time (unless it was previously
333 // released). So we detach the entry from the cache and reattach at release.
334 if (NULL != entry) {
335 fTextureCache->detach(entry);
336 }
337 return entry;
338}
339
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000340GrTextureEntry* GrContext::findApproximateKeylessTexture(
341 const GrTextureDesc& inDesc) {
342 GrTextureDesc desc = inDesc;
343 // bin by pow2 with a reasonable min
344 static const int MIN_SIZE = 256;
345 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth));
346 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight));
347
348 uint32_t p0 = desc.fFormat;
349 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags;
350
351 GrTextureEntry* entry;
352 bool keepTrying = true;
353 int origWidth = desc.fWidth;
354 int origHeight = desc.fHeight;
355 bool doubledW = false;
356 bool doubledH = false;
357
358 do {
359 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
360 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(), true);
361 entry = fTextureCache->findAndLock(key);
362
363 // if we miss, relax the fit of the flags...
364 // then try doubling width... then height.
365 if (NULL != entry) {
366 break;
367 }
368 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) {
369 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit;
370 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) {
371 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit;
372 } else if (!doubledW) {
373 desc.fFlags = inDesc.fFlags;
374 desc.fWidth *= 2;
375 doubledW = true;
376 } else if (!doubledH) {
377 desc.fFlags = inDesc.fFlags;
378 desc.fWidth = origWidth;
379 desc.fHeight *= 2;
380 doubledH = true;
381 } else {
382 break;
383 }
384
385 } while (true);
386
387 if (NULL == entry) {
388 desc.fFlags = inDesc.fFlags;
389 desc.fWidth = origWidth;
390 desc.fHeight = origHeight;
391 GrTexture* texture = fGpu->createTexture(desc, NULL, 0);
392 if (NULL != texture) {
393 GrTextureKey key(p0, p1, desc.fWidth, desc.fHeight);
394 this->finalizeTextureKey(&key, GrSamplerState::ClampNoFilter(),
395 true);
396 entry = fTextureCache->createAndLock(key, texture);
397 }
398 }
399
400 // If the caller gives us the same desc/sampler twice we don't want
401 // to return the same texture the second time (unless it was previously
402 // released). So we detach the entry from the cache and reattach at release.
403 if (NULL != entry) {
404 fTextureCache->detach(entry);
405 }
406 return entry;
407}
408
bsalomon@google.com27847de2011-02-22 20:59:41 +0000409void GrContext::unlockTexture(GrTextureEntry* entry) {
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000410 if (kKeylessBit & entry->key().getPrivateBits()) {
411 fTextureCache->reattachAndUnlock(entry);
412 } else {
413 fTextureCache->unlock(entry);
414 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000415}
416
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000417GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000418 void* srcData,
419 size_t rowBytes) {
420 return fGpu->createTexture(desc, srcData, rowBytes);
421}
422
423void GrContext::getTextureCacheLimits(int* maxTextures,
424 size_t* maxTextureBytes) const {
425 fTextureCache->getLimits(maxTextures, maxTextureBytes);
426}
427
428void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) {
429 fTextureCache->setLimits(maxTextures, maxTextureBytes);
430}
431
bsalomon@google.com91958362011-06-13 17:58:13 +0000432int GrContext::getMaxTextureSize() const {
433 return fGpu->maxTextureSize();
434}
435
436int GrContext::getMaxRenderTargetSize() const {
437 return fGpu->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000438}
439
440///////////////////////////////////////////////////////////////////////////////
441
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000442GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
443 // validate flags here so that GrGpu subclasses don't have to check
444 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
445 0 != desc.fRenderTargetFlags) {
446 return NULL;
447 }
448 if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
449 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
450 return NULL;
451 }
452 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
453 (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
454 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
455 return NULL;
456 }
457 return fGpu->createPlatformSurface(desc);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000458}
459
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000460GrRenderTarget* GrContext::createRenderTargetFrom3DApiState() {
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000461 return fGpu->createRenderTargetFrom3DApiState();
462}
463
bsalomon@google.com5877ffd2011-04-11 17:58:48 +0000464///////////////////////////////////////////////////////////////////////////////
465
bsalomon@google.com27847de2011-02-22 20:59:41 +0000466bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
467 int width, int height) {
468 if (!fGpu->supports8BitPalette()) {
469 return false;
470 }
471
472
473 bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
474
475 if (!isPow2) {
476 if (!fGpu->npotTextureSupport()) {
477 return false;
478 }
479
480 bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode ||
481 sampler.getWrapY() != GrSamplerState::kClamp_WrapMode;
482 if (tiled && !fGpu->npotTextureTileSupport()) {
483 return false;
484 }
485 }
486 return true;
487}
488
489////////////////////////////////////////////////////////////////////////////////
490
bsalomon@google.com05ef5102011-05-02 21:14:59 +0000491const GrClip& GrContext::getClip() const { return fGpu->getClip(); }
492
bsalomon@google.com27847de2011-02-22 20:59:41 +0000493void GrContext::setClip(const GrClip& clip) {
494 fGpu->setClip(clip);
495 fGpu->enableState(GrDrawTarget::kClip_StateBit);
496}
497
498void GrContext::setClip(const GrIRect& rect) {
499 GrClip clip;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000500 clip.setFromIRect(rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000501 fGpu->setClip(clip);
502}
503
504////////////////////////////////////////////////////////////////////////////////
505
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000506void GrContext::clear(const GrIRect* rect, const GrColor color) {
bsalomon@google.com398109c2011-04-14 18:40:27 +0000507 this->flush();
bsalomon@google.com6aa25c32011-04-27 19:55:29 +0000508 fGpu->clear(rect, color);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000509}
510
511void GrContext::drawPaint(const GrPaint& paint) {
512 // set rect to be big enough to fill the space, but not super-huge, so we
513 // don't overflow fixed-point implementations
bsalomon@google.comd302f142011-03-03 13:54:13 +0000514 GrRect r;
515 r.setLTRB(0, 0,
516 GrIntToScalar(getRenderTarget()->width()),
517 GrIntToScalar(getRenderTarget()->height()));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000518 GrMatrix inverse;
519 if (fGpu->getViewInverse(&inverse)) {
520 inverse.mapRect(&r);
521 } else {
522 GrPrintf("---- fGpu->getViewInverse failed\n");
523 }
524 this->drawRect(paint, r);
525}
526
bsalomon@google.com205d4602011-04-25 12:43:45 +0000527////////////////////////////////////////////////////////////////////////////////
528
bsalomon@google.com91958362011-06-13 17:58:13 +0000529struct GrContext::OffscreenRecord {
530 OffscreenRecord() { fEntry0 = NULL; fEntry1 = NULL; }
531 ~OffscreenRecord() { GrAssert(NULL == fEntry0 && NULL == fEntry1); }
532
533 enum Downsample {
534 k4x4TwoPass_Downsample,
535 k4x4SinglePass_Downsample,
536 kFSAA_Downsample
537 } fDownsample;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000538 int fTileSizeX;
539 int fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000540 int fTileCountX;
541 int fTileCountY;
542 int fScale;
543 GrTextureEntry* fEntry0;
544 GrTextureEntry* fEntry1;
545 GrDrawTarget::SavedDrawState fSavedState;
546};
547
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000548bool GrContext::doOffscreenAA(GrDrawTarget* target,
549 const GrPaint& paint,
550 bool isLines) const {
bsalomon@google.com91958362011-06-13 17:58:13 +0000551#if !GR_USE_OFFSCREEN_AA
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000552 return false;
553#else
554 if (!paint.fAntiAlias) {
555 return false;
556 }
557 if (isLines && fGpu->supportsAALines()) {
558 return false;
559 }
560 if (target->getRenderTarget()->isMultisampled()) {
561 return false;
562 }
563 // we have to be sure that the blend equation is expressible
564 // as simple src / dst coeffecients when the source
565 // is already modulated by the coverage fraction.
566 // We could use dual-source blending to get the correct per-pixel
567 // dst coeffecient for the remaining cases.
568 if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
569 kOne_BlendCoeff != paint.fDstBlendCoeff &&
570 kISA_BlendCoeff != paint.fDstBlendCoeff) {
571 return false;
572 }
573 return true;
574#endif
575}
576
bsalomon@google.com91958362011-06-13 17:58:13 +0000577bool GrContext::prepareForOffscreenAA(GrDrawTarget* target,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000578 bool requireStencil,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000579 const GrIRect& boundRect,
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000580 OffscreenRecord* record) {
bsalomon@google.com91958362011-06-13 17:58:13 +0000581
582 GrAssert(GR_USE_OFFSCREEN_AA);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000583
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000584 GrAssert(NULL == record->fEntry0);
585 GrAssert(NULL == record->fEntry1);
bsalomon@google.com91958362011-06-13 17:58:13 +0000586 GrAssert(!boundRect.isEmpty());
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000587
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000588 int boundW = boundRect.width();
589 int boundH = boundRect.height();
bsalomon@google.com91958362011-06-13 17:58:13 +0000590
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000591 GrTextureDesc desc;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000592
593 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW);
594 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH);
595
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000596 if (requireStencil) {
597 desc.fFlags = kRenderTarget_GrTextureFlagBit;
598 } else {
599 desc.fFlags = kRenderTarget_GrTextureFlagBit |
600 kNoStencil_GrTextureFlagBit;
601 }
602
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000603 desc.fFormat = kRGBA_8888_GrPixelConfig;
604
bsalomon@google.com91958362011-06-13 17:58:13 +0000605 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->supportsFullsceneAA()) {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000606 record->fDownsample = OffscreenRecord::kFSAA_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000607 record->fScale = GR_Scalar1;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000608 desc.fAALevel = kMed_GrAALevel;
609 } else {
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000610 record->fDownsample = (fGpu->supports4x4DownsampleFilter()) ?
611 OffscreenRecord::k4x4SinglePass_Downsample :
612 OffscreenRecord::k4x4TwoPass_Downsample;
bsalomon@google.com91958362011-06-13 17:58:13 +0000613 record->fScale = OFFSCREEN_SSAA_SCALE;
614 // both downsample paths assume this
615 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000616 desc.fAALevel = kNone_GrAALevel;
617 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000618
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000619 desc.fWidth *= record->fScale;
620 desc.fHeight *= record->fScale;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000621
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000622 record->fEntry0 = this->findApproximateKeylessTexture(desc);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000623 if (NULL == record->fEntry0) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000624 return false;
625 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000626 // the approximate lookup might have given us some slop space, might as well
627 // use it when computing the tiles size.
628 // these are scale values, will adjust after considering
629 // the possible second offscreen.
630 record->fTileSizeX = record->fEntry0->texture()->width();
631 record->fTileSizeY = record->fEntry0->texture()->height();
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000632
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000633 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000634 desc.fWidth /= 2;
635 desc.fHeight /= 2;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000636 record->fEntry1 = this->findApproximateKeylessTexture(desc);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000637 if (NULL == record->fEntry1) {
638 this->unlockTexture(record->fEntry0);
639 record->fEntry0 = NULL;
640 return false;
641 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000642 record->fTileSizeX = GrMin(record->fTileSizeX,
643 2 * record->fEntry0->texture()->width());
644 record->fTileSizeY = GrMin(record->fTileSizeY,
645 2 * record->fEntry0->texture()->height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000646 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000647 record->fTileSizeX /= record->fScale;
648 record->fTileSizeY /= record->fScale;
649
650 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX);
651 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY);
652
bsalomon@google.com91958362011-06-13 17:58:13 +0000653 target->saveCurrentDrawState(&record->fSavedState);
654 return true;
655}
656
657void GrContext::setupOffscreenAAPass1(GrDrawTarget* target,
658 const GrIRect& boundRect,
659 int tileX, int tileY,
660 OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000661
662 GrRenderTarget* offRT0 = record->fEntry0->texture()->asRenderTarget();
663 GrAssert(NULL != offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000664
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000665 GrPaint tempPaint;
666 tempPaint.reset();
667 SetPaint(tempPaint, target);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000668 target->setRenderTarget(offRT0);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000669
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000670 GrMatrix transM;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000671 int left = boundRect.fLeft + tileX * record->fTileSizeX;
672 int top = boundRect.fTop + tileY * record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000673 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000674 target->postConcatViewMatrix(transM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000675 GrMatrix scaleM;
bsalomon@google.com91958362011-06-13 17:58:13 +0000676 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000677 target->postConcatViewMatrix(scaleM);
678
679 // clip gets applied in second pass
680 target->disableState(GrDrawTarget::kClip_StateBit);
681
bsalomon@google.com91958362011-06-13 17:58:13 +0000682 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000683 record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000684 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000685 record->fTileSizeY;
bsalomon@google.com91958362011-06-13 17:58:13 +0000686 GrIRect clear = SkIRect::MakeWH(record->fScale * w,
687 record->fScale * h);
688#if 0
689 // visualize tile boundaries by setting edges of offscreen to white
690 // and interior to tranparent. black.
691 target->clear(&clear, 0xffffffff);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000692
bsalomon@google.com91958362011-06-13 17:58:13 +0000693 static const int gOffset = 2;
694 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset,
695 record->fScale * w - gOffset,
696 record->fScale * h - gOffset);
697 target->clear(&clear2, 0x0);
698#else
699 target->clear(&clear, 0x0);
700#endif
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000701}
702
bsalomon@google.com91958362011-06-13 17:58:13 +0000703void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000704 const GrPaint& paint,
705 const GrIRect& boundRect,
bsalomon@google.com91958362011-06-13 17:58:13 +0000706 int tileX, int tileY,
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000707 OffscreenRecord* record) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000708
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000709 GrAssert(NULL != record->fEntry0);
bsalomon@google.com91958362011-06-13 17:58:13 +0000710
711 GrIRect tileRect;
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000712 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
713 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
bsalomon@google.com91958362011-06-13 17:58:13 +0000714 tileRect.fRight = (tileX == record->fTileCountX-1) ?
715 boundRect.fRight :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000716 tileRect.fLeft + record->fTileSizeX;
bsalomon@google.com91958362011-06-13 17:58:13 +0000717 tileRect.fBottom = (tileY == record->fTileCountY-1) ?
718 boundRect.fBottom :
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000719 tileRect.fTop + record->fTileSizeY;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000720
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000721 GrSamplerState::Filter filter;
722 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) {
723 filter = GrSamplerState::k4x4Downsample_Filter;
724 } else {
725 filter = GrSamplerState::kBilinear_Filter;
726 }
727
bsalomon@google.coma47a48d2011-04-26 20:22:11 +0000728 GrMatrix sampleM;
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000729 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode,
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000730 GrSamplerState::kClamp_WrapMode, filter);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000731
732 GrTexture* src = record->fEntry0->texture();
733 int scale;
734
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000735 enum {
736 kOffscreenStage = GrPaint::kTotalStages,
737 };
738
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000739 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) {
740 GrAssert(NULL != record->fEntry1);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000741 scale = 2;
742 GrRenderTarget* dst = record->fEntry1->texture()->asRenderTarget();
743
744 // Do 2x2 downsample from first to second
745 target->setTexture(kOffscreenStage, src);
746 target->setRenderTarget(dst);
747 target->setViewMatrix(GrMatrix::I());
748 sampleM.setScale(scale * GR_Scalar1 / src->width(),
749 scale * GR_Scalar1 / src->height());
750 sampler.setMatrix(sampleM);
751 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com91958362011-06-13 17:58:13 +0000752 GrRect rect = SkRect::MakeWH(scale * tileRect.width(),
753 scale * tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000754 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage);
755
756 src = record->fEntry1->texture();
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000757 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000758 scale = 1;
bsalomon@google.com91958362011-06-13 17:58:13 +0000759 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height());
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000760 src->asRenderTarget()->overrideResolveRect(rect);
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000761 } else {
762 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample ==
763 record->fDownsample);
764 scale = 4;
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000765 }
766
bsalomon@google.com91958362011-06-13 17:58:13 +0000767 // setup for draw back to main RT, we use the original
768 // draw state setup by the caller plus an additional coverage
769 // stage to handle the AA resolve. Also, we use an identity
770 // view matrix and so pre-concat sampler matrices with view inv.
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000771 int stageMask = paint.getActiveStageMask();
772
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000773 target->restoreDrawState(record->fSavedState);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000774
775 if (stageMask) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000776 GrMatrix invVM;
777 if (target->getViewInverse(&invVM)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000778 target->preConcatSamplerMatrices(stageMask, invVM);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000779 }
780 }
bsalomon@google.com91958362011-06-13 17:58:13 +0000781 // This is important when tiling, otherwise second tile's
782 // pass 1 view matrix will be incorrect.
783 GrDrawTarget::AutoViewMatrixRestore avmr(target);
784
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000785 target->setViewMatrix(GrMatrix::I());
786
787 target->setTexture(kOffscreenStage, src);
788 sampleM.setScale(scale * GR_Scalar1 / src->width(),
789 scale * GR_Scalar1 / src->height());
790 sampler.setMatrix(sampleM);
bsalomon@google.com91958362011-06-13 17:58:13 +0000791 sampleM.setTranslate(-tileRect.fLeft, -tileRect.fTop);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000792 sampler.preConcatMatrix(sampleM);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000793 target->setSamplerState(kOffscreenStage, sampler);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000794
reed@google.com20efde72011-05-09 17:00:02 +0000795 GrRect dstRect;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000796 int stages = (1 << kOffscreenStage) | stageMask;
bsalomon@google.com91958362011-06-13 17:58:13 +0000797 dstRect.set(tileRect);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000798 target->drawSimpleRect(dstRect, NULL, stages);
bsalomon@google.com91958362011-06-13 17:58:13 +0000799}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000800
bsalomon@google.com91958362011-06-13 17:58:13 +0000801void GrContext::cleanupOffscreenAA(GrDrawTarget* target, OffscreenRecord* record) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000802 this->unlockTexture(record->fEntry0);
803 record->fEntry0 = NULL;
bsalomon@google.com6aef1fb2011-05-05 12:33:22 +0000804 if (NULL != record->fEntry1) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000805 this->unlockTexture(record->fEntry1);
806 record->fEntry1 = NULL;
807 }
808 target->restoreDrawState(record->fSavedState);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000809}
810
811////////////////////////////////////////////////////////////////////////////////
812
bsalomon@google.com27847de2011-02-22 20:59:41 +0000813/* create a triangle strip that strokes the specified triangle. There are 8
814 unique vertices, but we repreat the last 2 to close up. Alternatively we
815 could use an indices array, and then only send 8 verts, but not sure that
816 would be faster.
817 */
bsalomon@google.com205d4602011-04-25 12:43:45 +0000818static void setStrokeRectStrip(GrPoint verts[10], GrRect rect,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000819 GrScalar width) {
820 const GrScalar rad = GrScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000821 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000822
823 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
824 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
825 verts[2].set(rect.fRight - rad, rect.fTop + rad);
826 verts[3].set(rect.fRight + rad, rect.fTop - rad);
827 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
828 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
829 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
830 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
831 verts[8] = verts[0];
832 verts[9] = verts[1];
833}
834
bsalomon@google.com205d4602011-04-25 12:43:45 +0000835static GrColor getColorForMesh(const GrPaint& paint) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000836 // FIXME: This was copied from SkGpuDevice, seems like
837 // we should have already smeared a in caller if that
838 // is what is desired.
839 if (paint.hasTexture()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000840 unsigned a = GrColorUnpackA(paint.fColor);
841 return GrColorPackRGBA(a, a, a, a);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000842 } else {
843 return paint.fColor;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000844 }
845}
846
847static void setInsetFan(GrPoint* pts, size_t stride,
848 const GrRect& r, GrScalar dx, GrScalar dy) {
849 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
850}
851
852static const uint16_t gFillAARectIdx[] = {
853 0, 1, 5, 5, 4, 0,
854 1, 2, 6, 6, 5, 1,
855 2, 3, 7, 7, 6, 2,
856 3, 0, 4, 4, 7, 3,
857 4, 5, 6, 6, 7, 4,
858};
859
860int GrContext::aaFillRectIndexCount() const {
861 return GR_ARRAY_COUNT(gFillAARectIdx);
862}
863
864GrIndexBuffer* GrContext::aaFillRectIndexBuffer() {
865 if (NULL == fAAFillRectIndexBuffer) {
866 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx),
867 false);
868 GrAssert(NULL != fAAFillRectIndexBuffer);
869#if GR_DEBUG
870 bool updated =
871#endif
872 fAAFillRectIndexBuffer->updateData(gFillAARectIdx,
873 sizeof(gFillAARectIdx));
874 GR_DEBUGASSERT(updated);
875 }
876 return fAAFillRectIndexBuffer;
877}
878
879static const uint16_t gStrokeAARectIdx[] = {
880 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
881 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
882 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
883 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
884
885 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
886 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
887 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
888 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
889
890 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
891 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
892 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
893 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
894};
895
896int GrContext::aaStrokeRectIndexCount() const {
897 return GR_ARRAY_COUNT(gStrokeAARectIdx);
898}
899
900GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() {
901 if (NULL == fAAStrokeRectIndexBuffer) {
902 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx),
903 false);
904 GrAssert(NULL != fAAStrokeRectIndexBuffer);
905#if GR_DEBUG
906 bool updated =
907#endif
908 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
909 sizeof(gStrokeAARectIdx));
910 GR_DEBUGASSERT(updated);
911 }
912 return fAAStrokeRectIndexBuffer;
913}
914
915void GrContext::fillAARect(GrDrawTarget* target,
916 const GrPaint& paint,
917 const GrRect& devRect) {
918
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000919 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
920 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000921
922 size_t vsize = GrDrawTarget::VertexSize(layout);
923
924 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
925
926 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
927
928 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
929 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
930
931 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf);
932 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf);
933
934 verts += sizeof(GrPoint);
935 for (int i = 0; i < 4; ++i) {
936 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
937 }
938
939 GrColor innerColor = getColorForMesh(paint);
940 verts += 4 * vsize;
941 for (int i = 0; i < 4; ++i) {
942 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
943 }
944
945 target->setIndexSourceToBuffer(this->aaFillRectIndexBuffer());
946
947 target->drawIndexed(kTriangles_PrimitiveType, 0,
948 0, 8, this->aaFillRectIndexCount());
949}
950
951void GrContext::strokeAARect(GrDrawTarget* target, const GrPaint& paint,
952 const GrRect& devRect, const GrVec& devStrokeSize) {
953 const GrScalar& dx = devStrokeSize.fX;
954 const GrScalar& dy = devStrokeSize.fY;
955 const GrScalar rx = GrMul(dx, GR_ScalarHalf);
956 const GrScalar ry = GrMul(dy, GR_ScalarHalf);
957
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000958 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL) |
959 GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000960
961 GrScalar spare;
962 {
963 GrScalar w = devRect.width() - dx;
964 GrScalar h = devRect.height() - dy;
965 spare = GrMin(w, h);
966 }
967
968 if (spare <= 0) {
969 GrRect r(devRect);
970 r.inset(-rx, -ry);
971 fillAARect(target, paint, r);
972 return;
973 }
974
975 size_t vsize = GrDrawTarget::VertexSize(layout);
976
977 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
978
979 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
980
981 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
982 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
983 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
984 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
985
986 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf);
987 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf);
988 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf);
989 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf);
990
991 verts += sizeof(GrPoint);
992 for (int i = 0; i < 4; ++i) {
993 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
994 }
995
996 GrColor innerColor = getColorForMesh(paint);
997 verts += 4 * vsize;
998 for (int i = 0; i < 8; ++i) {
999 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
1000 }
1001
1002 verts += 8 * vsize;
1003 for (int i = 0; i < 8; ++i) {
1004 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
1005 }
1006
1007 target->setIndexSourceToBuffer(aaStrokeRectIndexBuffer());
1008 target->drawIndexed(kTriangles_PrimitiveType,
1009 0, 0, 16, aaStrokeRectIndexCount());
1010}
1011
reed@google.com20efde72011-05-09 17:00:02 +00001012/**
1013 * Returns true if the rects edges are integer-aligned.
1014 */
1015static bool isIRect(const GrRect& r) {
1016 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) &&
1017 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom);
1018}
1019
bsalomon@google.com205d4602011-04-25 12:43:45 +00001020static bool apply_aa_to_rect(GrDrawTarget* target,
1021 GrGpu* gpu,
1022 const GrPaint& paint,
1023 const GrRect& rect,
1024 GrScalar width,
1025 const GrMatrix* matrix,
1026 GrMatrix* combinedMatrix,
1027 GrRect* devRect) {
1028 // we use a simple alpha ramp to do aa on axis-aligned rects
1029 // do AA with alpha ramp if the caller requested AA, the rect
1030 // will be axis-aligned,the render target is not
1031 // multisampled, and the rect won't land on integer coords.
1032
1033 if (!paint.fAntiAlias) {
1034 return false;
1035 }
1036
1037 if (target->getRenderTarget()->isMultisampled()) {
1038 return false;
1039 }
1040
1041 if (0 == width && gpu->supportsAALines()) {
1042 return false;
1043 }
1044
1045 if (!target->getViewMatrix().preservesAxisAlignment()) {
1046 return false;
1047 }
1048
1049 if (NULL != matrix &&
1050 !matrix->preservesAxisAlignment()) {
1051 return false;
1052 }
1053
1054 *combinedMatrix = target->getViewMatrix();
1055 if (NULL != matrix) {
1056 combinedMatrix->preConcat(*matrix);
1057 GrAssert(combinedMatrix->preservesAxisAlignment());
1058 }
1059
1060 combinedMatrix->mapRect(devRect, rect);
1061 devRect->sort();
1062
1063 if (width < 0) {
reed@google.com20efde72011-05-09 17:00:02 +00001064 return !isIRect(*devRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001065 } else {
1066 return true;
1067 }
1068}
1069
bsalomon@google.com27847de2011-02-22 20:59:41 +00001070void GrContext::drawRect(const GrPaint& paint,
1071 const GrRect& rect,
1072 GrScalar width,
1073 const GrMatrix* matrix) {
1074
bsalomon@google.com27847de2011-02-22 20:59:41 +00001075
1076 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001077 int stageMask = paint.getActiveStageMask();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001078
bsalomon@google.com205d4602011-04-25 12:43:45 +00001079 GrRect devRect = rect;
1080 GrMatrix combinedMatrix;
1081 bool doAA = apply_aa_to_rect(target, fGpu, paint, rect, width, matrix,
1082 &combinedMatrix, &devRect);
1083
1084 if (doAA) {
1085 GrDrawTarget::AutoViewMatrixRestore avm(target);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001086 if (stageMask) {
bsalomon@google.com205d4602011-04-25 12:43:45 +00001087 GrMatrix inv;
1088 if (combinedMatrix.invert(&inv)) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001089 target->preConcatSamplerMatrices(stageMask, inv);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001090 }
1091 }
1092 target->setViewMatrix(GrMatrix::I());
1093 if (width >= 0) {
1094 GrVec strokeSize;;
1095 if (width > 0) {
1096 strokeSize.set(width, width);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001097 combinedMatrix.mapVectors(&strokeSize, 1);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001098 strokeSize.setAbs(strokeSize);
1099 } else {
1100 strokeSize.set(GR_Scalar1, GR_Scalar1);
1101 }
1102 strokeAARect(target, paint, devRect, strokeSize);
1103 } else {
1104 fillAARect(target, paint, devRect);
1105 }
1106 return;
1107 }
1108
bsalomon@google.com27847de2011-02-22 20:59:41 +00001109 if (width >= 0) {
1110 // TODO: consider making static vertex buffers for these cases.
1111 // Hairline could be done by just adding closing vertex to
1112 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001113 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1114
bsalomon@google.com27847de2011-02-22 20:59:41 +00001115 static const int worstCaseVertCount = 10;
1116 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0);
1117
1118 if (!geo.succeeded()) {
1119 return;
1120 }
1121
1122 GrPrimitiveType primType;
1123 int vertCount;
1124 GrPoint* vertex = geo.positions();
1125
1126 if (width > 0) {
1127 vertCount = 10;
1128 primType = kTriangleStrip_PrimitiveType;
1129 setStrokeRectStrip(vertex, rect, width);
1130 } else {
1131 // hairline
1132 vertCount = 5;
1133 primType = kLineStrip_PrimitiveType;
1134 vertex[0].set(rect.fLeft, rect.fTop);
1135 vertex[1].set(rect.fRight, rect.fTop);
1136 vertex[2].set(rect.fRight, rect.fBottom);
1137 vertex[3].set(rect.fLeft, rect.fBottom);
1138 vertex[4].set(rect.fLeft, rect.fTop);
1139 }
1140
1141 GrDrawTarget::AutoViewMatrixRestore avmr;
1142 if (NULL != matrix) {
1143 avmr.set(target);
1144 target->preConcatViewMatrix(*matrix);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001145 target->preConcatSamplerMatrices(stageMask, *matrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001146 }
1147
1148 target->drawNonIndexed(primType, 0, vertCount);
1149 } else {
1150 #if GR_STATIC_RECT_VB
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001151 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
1152
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001153 target->setVertexSourceToBuffer(layout,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001154 fGpu->getUnitSquareVertexBuffer());
1155 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1156 GrMatrix m;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001157 m.setAll(rect.width(), 0, rect.fLeft,
bsalomon@google.com205d4602011-04-25 12:43:45 +00001158 0, rect.height(), rect.fTop,
1159 0, 0, GrMatrix::I()[8]);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001160
1161 if (NULL != matrix) {
1162 m.postConcat(*matrix);
1163 }
1164
1165 target->preConcatViewMatrix(m);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001166 target->preConcatSamplerMatrices(stageMask, m);
1167
bsalomon@google.com27847de2011-02-22 20:59:41 +00001168 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1169 #else
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001170 target->drawSimpleRect(rect, matrix, stageMask);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001171 #endif
1172 }
1173}
1174
1175void GrContext::drawRectToRect(const GrPaint& paint,
1176 const GrRect& dstRect,
1177 const GrRect& srcRect,
1178 const GrMatrix* dstMatrix,
1179 const GrMatrix* srcMatrix) {
1180
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001181 // srcRect refers to paint's first texture
1182 if (NULL == paint.getTexture(0)) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001183 drawRect(paint, dstRect, -1, dstMatrix);
1184 return;
1185 }
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001186
bsalomon@google.com27847de2011-02-22 20:59:41 +00001187 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB);
1188
1189#if GR_STATIC_RECT_VB
1190 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001191
1192 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001193 GrDrawTarget::AutoViewMatrixRestore avmr(target);
1194
1195 GrMatrix m;
1196
1197 m.setAll(dstRect.width(), 0, dstRect.fLeft,
1198 0, dstRect.height(), dstRect.fTop,
1199 0, 0, GrMatrix::I()[8]);
1200 if (NULL != dstMatrix) {
1201 m.postConcat(*dstMatrix);
1202 }
1203 target->preConcatViewMatrix(m);
1204
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001205 // srcRect refers to first stage
1206 int otherStageMask = paint.getActiveStageMask() &
1207 (~(1 << GrPaint::kFirstTextureStage));
1208 if (otherStageMask) {
1209 target->preConcatSamplerMatrices(otherStageMask, m);
1210 }
1211
bsalomon@google.com27847de2011-02-22 20:59:41 +00001212 m.setAll(srcRect.width(), 0, srcRect.fLeft,
1213 0, srcRect.height(), srcRect.fTop,
1214 0, 0, GrMatrix::I()[8]);
1215 if (NULL != srcMatrix) {
1216 m.postConcat(*srcMatrix);
1217 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001218 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001219
1220 target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer());
1221 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4);
1222#else
1223
1224 GrDrawTarget* target;
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001225#if BATCH_RECT_TO_RECT
bsalomon@google.com27847de2011-02-22 20:59:41 +00001226 target = this->prepareToDraw(paint, kBuffered_DrawCategory);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001227#else
bsalomon@google.com27847de2011-02-22 20:59:41 +00001228 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1229#endif
1230
1231 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL};
1232 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL};
1233 srcRects[0] = &srcRect;
1234 srcMatrices[0] = srcMatrix;
1235
1236 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices);
1237#endif
1238}
1239
1240void GrContext::drawVertices(const GrPaint& paint,
1241 GrPrimitiveType primitiveType,
1242 int vertexCount,
1243 const GrPoint positions[],
1244 const GrPoint texCoords[],
1245 const GrColor colors[],
1246 const uint16_t indices[],
1247 int indexCount) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001248
1249 GrDrawTarget::AutoReleaseGeometry geo;
1250
1251 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
1252
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001253 bool hasTexCoords[GrPaint::kTotalStages] = {
1254 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords
1255 0 // remaining stages use positions
1256 };
1257
1258 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001259
1260 if (NULL != colors) {
1261 layout |= GrDrawTarget::kColor_VertexLayoutBit;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001262 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001263 int vertexSize = GrDrawTarget::VertexSize(layout);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001264
1265 if (sizeof(GrPoint) != vertexSize) {
1266 if (!geo.set(target, layout, vertexCount, 0)) {
1267 GrPrintf("Failed to get space for vertices!");
1268 return;
1269 }
1270 int texOffsets[GrDrawTarget::kMaxTexCoords];
1271 int colorOffset;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001272 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout,
1273 texOffsets,
1274 &colorOffset);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001275 void* curVertex = geo.vertices();
1276
1277 for (int i = 0; i < vertexCount; ++i) {
1278 *((GrPoint*)curVertex) = positions[i];
1279
1280 if (texOffsets[0] > 0) {
1281 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i];
1282 }
1283 if (colorOffset > 0) {
1284 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
1285 }
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001286 curVertex = (void*)((intptr_t)curVertex + vertexSize);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001287 }
1288 } else {
1289 target->setVertexSourceToArray(layout, positions, vertexCount);
1290 }
1291
bsalomon@google.com91958362011-06-13 17:58:13 +00001292 // we don't currently apply offscreen AA to this path. Need improved
1293 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001294
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001295 if (NULL != indices) {
bsalomon@google.com91958362011-06-13 17:58:13 +00001296 target->setIndexSourceToArray(indices, indexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001297 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001298 } else {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001299 target->drawNonIndexed(primitiveType, 0, vertexCount);
1300 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001301}
1302
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001303///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com27847de2011-02-22 20:59:41 +00001304
reed@google.com07f3ee12011-05-16 17:21:57 +00001305void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
1306 GrPathFill fill, const GrPoint* translate) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001307
bsalomon@google.com27847de2011-02-22 20:59:41 +00001308 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001309 GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001310
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001311 if (!pr->supportsAA(target, path, fill) &&
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001312 this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001313
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001314 bool needsStencil = pr->requiresStencilPass(target, path, fill);
bsalomon@google.coma47a48d2011-04-26 20:22:11 +00001315
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001316 // compute bounds as intersection of rt size, clip, and path
reed@google.com20efde72011-05-09 17:00:02 +00001317 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(),
1318 target->getRenderTarget()->height());
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001319 GrIRect clipIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001320 if (target->getClip().hasConservativeBounds()) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001321 target->getClip().getConservativeBounds().roundOut(&clipIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001322 if (!bound.intersect(clipIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001323 return;
1324 }
1325 }
reed@google.com70c136e2011-06-03 19:51:26 +00001326
reed@google.com07f3ee12011-05-16 17:21:57 +00001327 GrRect pathBounds = path.getBounds();
1328 if (!pathBounds.isEmpty()) {
bsalomon@google.com7ca72f32011-06-07 18:46:50 +00001329 if (NULL != translate) {
1330 pathBounds.offset(*translate);
1331 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001332 target->getViewMatrix().mapRect(&pathBounds, pathBounds);
bsalomon@google.com91958362011-06-13 17:58:13 +00001333 GrIRect pathIBounds;
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001334 pathBounds.roundOut(&pathIBounds);
reed@google.com20efde72011-05-09 17:00:02 +00001335 if (!bound.intersect(pathIBounds)) {
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001336 return;
1337 }
1338 }
bsalomon@google.com91958362011-06-13 17:58:13 +00001339 OffscreenRecord record;
1340 if (this->prepareForOffscreenAA(target, needsStencil, bound, &record)) {
1341 for (int tx = 0; tx < record.fTileCountX; ++tx) {
1342 for (int ty = 0; ty < record.fTileCountY; ++ty) {
1343 this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
1344 pr->drawPath(target, 0, path, fill, translate);
1345 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
1346 }
1347 }
1348 this->cleanupOffscreenAA(target, &record);
bsalomon@google.com7ac249b2011-06-14 18:46:24 +00001349 if (IsFillInverted(fill) && bound != clipIBounds) {
1350 int stageMask = paint.getActiveStageMask();
1351 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
1352 GrRect rect;
1353 if (clipIBounds.fTop < bound.fTop) {
1354 rect.setLTRB(clipIBounds.fLeft, clipIBounds.fTop,
1355 clipIBounds.fRight, bound.fTop);
1356 target->drawSimpleRect(rect, NULL, stageMask);
1357 }
1358 if (clipIBounds.fLeft < bound.fLeft) {
1359 rect.setLTRB(clipIBounds.fLeft, bound.fTop,
1360 bound.fLeft, bound.fBottom);
1361 target->drawSimpleRect(rect, NULL, stageMask);
1362 }
1363 if (clipIBounds.fRight > bound.fRight) {
1364 rect.setLTRB(bound.fRight, bound.fTop,
1365 clipIBounds.fRight, bound.fBottom);
1366 target->drawSimpleRect(rect, NULL, stageMask);
1367 }
1368 if (clipIBounds.fBottom > bound.fBottom) {
1369 rect.setLTRB(clipIBounds.fLeft, bound.fBottom,
1370 clipIBounds.fRight, clipIBounds.fBottom);
1371 target->drawSimpleRect(rect, NULL, stageMask);
1372 }
1373 }
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001374 return;
1375 }
reed@google.com70c136e2011-06-03 19:51:26 +00001376 }
1377
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001378 GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001379
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001380 pr->drawPath(target, enabledStages, path, fill, translate);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001381}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001382
bsalomon@google.com27847de2011-02-22 20:59:41 +00001383////////////////////////////////////////////////////////////////////////////////
1384
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001385void GrContext::flush(int flagsBitfield) {
1386 if (kDiscard_FlushBit & flagsBitfield) {
1387 fDrawBuffer->reset();
1388 } else {
1389 flushDrawBuffer();
1390 }
1391
1392 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001393 fGpu->forceRenderTargetFlush();
1394 }
1395}
1396
1397void GrContext::flushText() {
1398 if (kText_DrawCategory == fLastDrawCategory) {
1399 flushDrawBuffer();
1400 }
1401}
1402
1403void GrContext::flushDrawBuffer() {
1404#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING
junov@google.com53a55842011-06-08 22:55:10 +00001405 if (fDrawBuffer) {
1406 fDrawBuffer->playback(fGpu);
1407 fDrawBuffer->reset();
1408 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001409#endif
1410}
1411
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001412bool GrContext::readTexturePixels(GrTexture* texture,
1413 int left, int top, int width, int height,
1414 GrPixelConfig config, void* buffer) {
1415
1416 // TODO: code read pixels for textures that aren't rendertargets
1417
1418 this->flush();
1419 GrRenderTarget* target = texture->asRenderTarget();
1420 if (NULL != target) {
1421 return fGpu->readPixels(target,
1422 left, top, width, height,
1423 config, buffer);
1424 } else {
1425 return false;
1426 }
1427}
1428
1429bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1430 int left, int top, int width, int height,
1431 GrPixelConfig config, void* buffer) {
1432 uint32_t flushFlags = 0;
1433 if (NULL == target) {
1434 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
1435 }
1436
1437 this->flush(flushFlags);
1438 return fGpu->readPixels(target,
1439 left, top, width, height,
1440 config, buffer);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001441}
1442
1443void GrContext::writePixels(int left, int top, int width, int height,
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001444 GrPixelConfig config, const void* buffer,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001445 size_t stride) {
1446
1447 // TODO: when underlying api has a direct way to do this we should use it
1448 // (e.g. glDrawPixels on desktop GL).
1449
bsalomon@google.comfea37b52011-04-25 15:51:06 +00001450 const GrTextureDesc desc = {
1451 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config
bsalomon@google.com27847de2011-02-22 20:59:41 +00001452 };
1453 GrTexture* texture = fGpu->createTexture(desc, buffer, stride);
1454 if (NULL == texture) {
1455 return;
1456 }
1457
1458 this->flush(true);
1459
1460 GrAutoUnref aur(texture);
1461 GrDrawTarget::AutoStateRestore asr(fGpu);
1462
1463 GrMatrix matrix;
1464 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
1465 fGpu->setViewMatrix(matrix);
1466
kbr@chromium.org120bdff2011-06-07 01:27:01 +00001467 fGpu->setColorFilter(0, SkXfermode::kDst_Mode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001468 fGpu->disableState(GrDrawTarget::kClip_StateBit);
1469 fGpu->setAlpha(0xFF);
1470 fGpu->setBlendFunc(kOne_BlendCoeff,
1471 kZero_BlendCoeff);
1472 fGpu->setTexture(0, texture);
1473
1474 GrSamplerState sampler;
1475 sampler.setClampNoFilter();
1476 matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height);
1477 sampler.setMatrix(matrix);
1478 fGpu->setSamplerState(0, sampler);
1479
1480 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0);
1481 static const int VCOUNT = 4;
1482
1483 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0);
1484 if (!geo.succeeded()) {
1485 return;
1486 }
1487 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height);
1488 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT);
1489}
1490////////////////////////////////////////////////////////////////////////////////
1491
1492void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +00001493
1494 for (int i = 0; i < GrPaint::kMaxTextures; ++i) {
1495 int s = i + GrPaint::kFirstTextureStage;
1496 target->setTexture(s, paint.getTexture(i));
1497 target->setSamplerState(s, *paint.getTextureSampler(i));
1498 }
1499
1500 target->setFirstCoverageStage(GrPaint::kFirstMaskStage);
1501
1502 for (int i = 0; i < GrPaint::kMaxMasks; ++i) {
1503 int s = i + GrPaint::kFirstMaskStage;
1504 target->setTexture(s, paint.getMask(i));
1505 target->setSamplerState(s, *paint.getMaskSampler(i));
1506 }
1507
bsalomon@google.com27847de2011-02-22 20:59:41 +00001508 target->setColor(paint.fColor);
1509
1510 if (paint.fDither) {
1511 target->enableState(GrDrawTarget::kDither_StateBit);
1512 } else {
1513 target->disableState(GrDrawTarget::kDither_StateBit);
1514 }
1515 if (paint.fAntiAlias) {
1516 target->enableState(GrDrawTarget::kAntialias_StateBit);
1517 } else {
1518 target->disableState(GrDrawTarget::kAntialias_StateBit);
1519 }
1520 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
Scroggo97c88c22011-05-11 14:05:25 +00001521 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001522}
1523
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001524GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001525 DrawCategory category) {
1526 if (category != fLastDrawCategory) {
1527 flushDrawBuffer();
1528 fLastDrawCategory = category;
1529 }
1530 SetPaint(paint, fGpu);
1531 GrDrawTarget* target = fGpu;
1532 switch (category) {
1533 case kText_DrawCategory:
1534#if DEFER_TEXT_RENDERING
1535 target = fDrawBuffer;
1536 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1537#else
1538 target = fGpu;
1539#endif
1540 break;
1541 case kUnbuffered_DrawCategory:
1542 target = fGpu;
1543 break;
1544 case kBuffered_DrawCategory:
1545 target = fDrawBuffer;
1546 fDrawBuffer->initializeDrawStateAndClip(*fGpu);
1547 break;
1548 }
1549 return target;
1550}
1551
1552////////////////////////////////////////////////////////////////////////////////
1553
bsalomon@google.com27847de2011-02-22 20:59:41 +00001554void GrContext::setRenderTarget(GrRenderTarget* target) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001555 this->flush(false);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001556 fGpu->setRenderTarget(target);
1557}
1558
1559GrRenderTarget* GrContext::getRenderTarget() {
1560 return fGpu->getRenderTarget();
1561}
1562
1563const GrRenderTarget* GrContext::getRenderTarget() const {
1564 return fGpu->getRenderTarget();
1565}
1566
1567const GrMatrix& GrContext::getMatrix() const {
1568 return fGpu->getViewMatrix();
1569}
1570
1571void GrContext::setMatrix(const GrMatrix& m) {
1572 fGpu->setViewMatrix(m);
1573}
1574
1575void GrContext::concatMatrix(const GrMatrix& m) const {
1576 fGpu->preConcatViewMatrix(m);
1577}
1578
1579static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) {
1580 intptr_t mask = 1 << shift;
1581 if (pred) {
1582 bits |= mask;
1583 } else {
1584 bits &= ~mask;
1585 }
1586 return bits;
1587}
1588
1589void GrContext::resetStats() {
1590 fGpu->resetStats();
1591}
1592
bsalomon@google.com05ef5102011-05-02 21:14:59 +00001593const GrGpuStats& GrContext::getStats() const {
bsalomon@google.com27847de2011-02-22 20:59:41 +00001594 return fGpu->getStats();
1595}
1596
1597void GrContext::printStats() const {
1598 fGpu->printStats();
1599}
1600
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001601GrContext::GrContext(GrGpu* gpu) :
1602 fDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
1603 gpu->supportsStencilWrapOps()) {
1604
bsalomon@google.com27847de2011-02-22 20:59:41 +00001605 fGpu = gpu;
1606 fGpu->ref();
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001607 fGpu->setContext(this);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001608
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001609 fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
1610 fGpu->setClipPathRenderer(fCustomPathRenderer);
1611
bsalomon@google.com27847de2011-02-22 20:59:41 +00001612 fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT,
1613 MAX_TEXTURE_CACHE_BYTES);
1614 fFontCache = new GrFontCache(fGpu);
1615
1616 fLastDrawCategory = kUnbuffered_DrawCategory;
1617
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001618 fDrawBuffer = NULL;
1619 fDrawBufferVBAllocPool = NULL;
1620 fDrawBufferIBAllocPool = NULL;
1621
bsalomon@google.com205d4602011-04-25 12:43:45 +00001622 fAAFillRectIndexBuffer = NULL;
1623 fAAStrokeRectIndexBuffer = NULL;
bsalomon@google.com91958362011-06-13 17:58:13 +00001624
1625 int gpuMaxOffscreen = fGpu->maxRenderTargetSize();
1626 if (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->supportsFullsceneAA()) {
1627 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE;
1628 }
1629 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen);
bsalomon@google.com205d4602011-04-25 12:43:45 +00001630
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001631 this->setupDrawBuffer();
1632}
1633
1634void GrContext::setupDrawBuffer() {
1635
1636 GrAssert(NULL == fDrawBuffer);
1637 GrAssert(NULL == fDrawBufferVBAllocPool);
1638 GrAssert(NULL == fDrawBufferIBAllocPool);
1639
bsalomon@google.com27847de2011-02-22 20:59:41 +00001640#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001641 fDrawBufferVBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001642 new GrVertexBufferAllocPool(fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001643 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1644 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS);
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001645 fDrawBufferIBAllocPool =
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001646 new GrIndexBufferAllocPool(fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001647 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001648 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS);
1649
1650 fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool,
1651 fDrawBufferIBAllocPool);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001652#endif
1653
1654#if BATCH_RECT_TO_RECT
1655 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer());
1656#endif
bsalomon@google.com27847de2011-02-22 20:59:41 +00001657}
1658
bsalomon@google.com27847de2011-02-22 20:59:41 +00001659GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) {
1660 GrDrawTarget* target;
1661#if DEFER_TEXT_RENDERING
1662 target = prepareToDraw(paint, kText_DrawCategory);
1663#else
1664 target = prepareToDraw(paint, kUnbuffered_DrawCategory);
1665#endif
1666 SetPaint(paint, target);
1667 return target;
1668}
1669
1670const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1671 return fGpu->getQuadIndexBuffer();
1672}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001673
1674GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
reed@google.com07f3ee12011-05-16 17:21:57 +00001675 const GrPath& path,
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001676 GrPathFill fill) {
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001677 if (NULL != fCustomPathRenderer &&
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001678 fCustomPathRenderer->canDrawPath(target, path, fill)) {
1679 return fCustomPathRenderer;
1680 } else {
1681 GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
1682 return &fDefaultPathRenderer;
1683 }
1684}
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001685