| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "GrContext.h" | 9 #include "GrContext.h" |
| 10 | 10 |
| 11 #include "GrAARectRenderer.h" | 11 #include "GrAARectRenderer.h" |
| 12 #include "GrAtlasTextContext.h" | 12 #include "GrAtlasTextContext.h" |
| 13 #include "GrBatch.h" | 13 #include "GrBatch.h" |
| 14 #include "GrBatchFontCache.h" | 14 #include "GrBatchFontCache.h" |
| 15 #include "GrBatchTarget.h" | 15 #include "GrBatchTarget.h" |
| 16 #include "GrBatchTest.h" | 16 #include "GrBatchTest.h" |
| 17 #include "GrCaps.h" | 17 #include "GrCaps.h" |
| 18 #include "GrContextOptions.h" | 18 #include "GrContextOptions.h" |
| 19 #include "GrDefaultGeoProcFactory.h" | 19 #include "GrDefaultGeoProcFactory.h" |
| 20 #include "GrDrawContext.h" |
| 20 #include "GrGpuResource.h" | 21 #include "GrGpuResource.h" |
| 21 #include "GrGpuResourcePriv.h" | 22 #include "GrGpuResourcePriv.h" |
| 22 #include "GrGpu.h" | 23 #include "GrGpu.h" |
| 23 #include "GrImmediateDrawTarget.h" | 24 #include "GrImmediateDrawTarget.h" |
| 24 #include "GrIndexBuffer.h" | 25 #include "GrIndexBuffer.h" |
| 25 #include "GrInOrderDrawBuffer.h" | 26 #include "GrInOrderDrawBuffer.h" |
| 26 #include "GrLayerCache.h" | 27 #include "GrLayerCache.h" |
| 27 #include "GrOvalRenderer.h" | 28 #include "GrOvalRenderer.h" |
| 28 #include "GrPathRenderer.h" | 29 #include "GrPathRenderer.h" |
| 29 #include "GrPathUtils.h" | 30 #include "GrPathUtils.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 46 #include "SkStrokeRec.h" | 47 #include "SkStrokeRec.h" |
| 47 #include "SkTLazy.h" | 48 #include "SkTLazy.h" |
| 48 #include "SkTLS.h" | 49 #include "SkTLS.h" |
| 49 #include "SkTraceEvent.h" | 50 #include "SkTraceEvent.h" |
| 50 | 51 |
| 51 #include "effects/GrConfigConversionEffect.h" | 52 #include "effects/GrConfigConversionEffect.h" |
| 52 #include "effects/GrDashingEffect.h" | 53 #include "effects/GrDashingEffect.h" |
| 53 #include "effects/GrSingleTextureEffect.h" | 54 #include "effects/GrSingleTextureEffect.h" |
| 54 | 55 |
| 55 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) | 56 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) |
| 56 #define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; } | 57 #define RETURN_IF_ABANDONED if (fDrawingMgr.abandoned()) { return; } |
| 57 #define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; } | 58 #define RETURN_FALSE_IF_ABANDONED if (fDrawingMgr.abandoned()) { return false; } |
| 58 #define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; } | 59 #define RETURN_NULL_IF_ABANDONED if (fDrawingMgr.abandoned()) { return NULL; } |
| 59 | 60 |
| 60 class GrContext::AutoCheckFlush { | |
| 61 public: | |
| 62 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} | |
| 63 | 61 |
| 64 ~AutoCheckFlush() { | 62 //////////////////////////////////////////////////////////////////////////////// |
| 65 if (fContext->fFlushToReduceCacheSize) { | 63 |
| 66 fContext->flush(); | 64 void GrContext::DrawingMgr::init(GrContext* context) { |
| 67 } | 65 #ifdef IMMEDIATE_MODE |
| 66 fDrawTarget = SkNEW_ARGS(GrImmediateDrawTarget, (context)); |
| 67 #else |
| 68 fDrawTarget = SkNEW_ARGS(GrInOrderDrawBuffer, (context)); |
| 69 #endif |
| 70 |
| 71 fDrawContext = SkNEW_ARGS(GrDrawContext, (context, fDrawTarget)); |
| 72 } |
| 73 |
| 74 GrContext::DrawingMgr::~DrawingMgr() { |
| 75 SkSafeUnref(fDrawTarget); |
| 76 SkSafeUnref(fDrawContext); |
| 77 } |
| 78 |
| 79 void GrContext::DrawingMgr::abandon() { |
| 80 SkSafeSetNull(fDrawTarget); |
| 81 fDrawContext->fDrawTarget.reset(NULL); |
| 82 SkSafeSetNull(fDrawContext); |
| 83 } |
| 84 |
| 85 void GrContext::DrawingMgr::purgeResources() { |
| 86 if (fDrawTarget) { |
| 87 fDrawTarget->purgeResources(); |
| 68 } | 88 } |
| 89 } |
| 69 | 90 |
| 70 private: | 91 void GrContext::DrawingMgr::reset() { |
| 71 GrContext* fContext; | 92 if (fDrawTarget) { |
| 72 }; | 93 fDrawTarget->reset(); |
| 94 } |
| 95 } |
| 96 |
| 97 void GrContext::DrawingMgr::flush() { |
| 98 if (fDrawTarget) { |
| 99 fDrawTarget->flush(); |
| 100 } |
| 101 } |
| 102 |
| 103 GrDrawContext* GrContext::DrawingMgr::drawContext() { |
| 104 if (this->abandoned()) { |
| 105 return NULL; |
| 106 } |
| 107 return fDrawContext; |
| 108 } |
| 109 |
| 110 //////////////////////////////////////////////////////////////////////////////// |
| 111 |
| 73 | 112 |
| 74 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext)
{ | 113 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext)
{ |
| 75 GrContextOptions defaultOptions; | 114 GrContextOptions defaultOptions; |
| 76 return Create(backend, backendContext, defaultOptions); | 115 return Create(backend, backendContext, defaultOptions); |
| 77 } | 116 } |
| 78 | 117 |
| 79 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, | 118 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, |
| 80 const GrContextOptions& options) { | 119 const GrContextOptions& options) { |
| 81 GrContext* context = SkNEW(GrContext); | 120 GrContext* context = SkNEW(GrContext); |
| 82 | 121 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 97 return id; | 136 return id; |
| 98 } | 137 } |
| 99 | 138 |
| 100 GrContext::GrContext() : fUniqueID(next_id()) { | 139 GrContext::GrContext() : fUniqueID(next_id()) { |
| 101 fGpu = NULL; | 140 fGpu = NULL; |
| 102 fResourceCache = NULL; | 141 fResourceCache = NULL; |
| 103 fResourceProvider = NULL; | 142 fResourceProvider = NULL; |
| 104 fPathRendererChain = NULL; | 143 fPathRendererChain = NULL; |
| 105 fSoftwarePathRenderer = NULL; | 144 fSoftwarePathRenderer = NULL; |
| 106 fBatchFontCache = NULL; | 145 fBatchFontCache = NULL; |
| 107 fDrawBuffer = NULL; | |
| 108 fFlushToReduceCacheSize = false; | 146 fFlushToReduceCacheSize = false; |
| 109 fAARectRenderer = NULL; | |
| 110 fOvalRenderer = NULL; | |
| 111 fMaxTextureSizeOverride = 1 << 20; | 147 fMaxTextureSizeOverride = 1 << 20; |
| 112 } | 148 } |
| 113 | 149 |
| 114 bool GrContext::init(GrBackend backend, GrBackendContext backendContext, | 150 bool GrContext::init(GrBackend backend, GrBackendContext backendContext, |
| 115 const GrContextOptions& options) { | 151 const GrContextOptions& options) { |
| 116 SkASSERT(NULL == fGpu); | 152 SkASSERT(!fGpu); |
| 117 | 153 |
| 118 fGpu = GrGpu::Create(backend, backendContext, options, this); | 154 fGpu = GrGpu::Create(backend, backendContext, options, this); |
| 119 if (NULL == fGpu) { | 155 if (!fGpu) { |
| 120 return false; | 156 return false; |
| 121 } | 157 } |
| 122 this->initCommon(); | 158 this->initCommon(); |
| 123 return true; | 159 return true; |
| 124 } | 160 } |
| 125 | 161 |
| 126 void GrContext::initCommon() { | 162 void GrContext::initCommon() { |
| 127 fResourceCache = SkNEW(GrResourceCache); | 163 fResourceCache = SkNEW(GrResourceCache); |
| 128 fResourceCache->setOverBudgetCallback(OverBudgetCB, this); | 164 fResourceCache->setOverBudgetCallback(OverBudgetCB, this); |
| 129 fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache)); | 165 fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache)); |
| 130 | 166 |
| 131 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this))); | 167 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this))); |
| 132 | 168 |
| 133 fAARectRenderer = SkNEW(GrAARectRenderer); | |
| 134 fOvalRenderer = SkNEW(GrOvalRenderer); | |
| 135 | |
| 136 fDidTestPMConversions = false; | 169 fDidTestPMConversions = false; |
| 137 | 170 |
| 138 #ifdef IMMEDIATE_MODE | 171 fDrawingMgr.init(this); |
| 139 fDrawBuffer = SkNEW_ARGS(GrImmediateDrawTarget, (this)); | |
| 140 #else | |
| 141 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (this)); | |
| 142 #endif | |
| 143 | 172 |
| 144 // GrBatchFontCache will eventually replace GrFontCache | 173 // GrBatchFontCache will eventually replace GrFontCache |
| 145 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this)); | 174 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this)); |
| 146 | 175 |
| 147 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB,
this))); | 176 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB,
this))); |
| 148 } | 177 } |
| 149 | 178 |
| 150 GrContext::~GrContext() { | 179 GrContext::~GrContext() { |
| 151 if (NULL == fGpu) { | 180 if (!fGpu) { |
| 152 return; | 181 return; |
| 153 } | 182 } |
| 154 | 183 |
| 155 this->flush(); | 184 this->flush(); |
| 156 | 185 |
| 157 for (int i = 0; i < fCleanUpData.count(); ++i) { | 186 for (int i = 0; i < fCleanUpData.count(); ++i) { |
| 158 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); | 187 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); |
| 159 } | 188 } |
| 160 | 189 |
| 161 SkDELETE(fResourceProvider); | 190 SkDELETE(fResourceProvider); |
| 162 SkDELETE(fResourceCache); | 191 SkDELETE(fResourceCache); |
| 163 SkDELETE(fBatchFontCache); | 192 SkDELETE(fBatchFontCache); |
| 164 SkDELETE(fDrawBuffer); | |
| 165 | |
| 166 fAARectRenderer->unref(); | |
| 167 fOvalRenderer->unref(); | |
| 168 | 193 |
| 169 fGpu->unref(); | 194 fGpu->unref(); |
| 170 SkSafeUnref(fPathRendererChain); | 195 SkSafeUnref(fPathRendererChain); |
| 171 SkSafeUnref(fSoftwarePathRenderer); | 196 SkSafeUnref(fSoftwarePathRenderer); |
| 172 } | 197 } |
| 173 | 198 |
| 174 void GrContext::abandonContext() { | 199 void GrContext::abandonContext() { |
| 175 fResourceProvider->abandon(); | 200 fResourceProvider->abandon(); |
| 176 // abandon first to so destructors | 201 // abandon first to so destructors |
| 177 // don't try to free the resources in the API. | 202 // don't try to free the resources in the API. |
| 178 fResourceCache->abandonAll(); | 203 fResourceCache->abandonAll(); |
| 179 | 204 |
| 180 fGpu->contextAbandoned(); | 205 fGpu->contextAbandoned(); |
| 181 | 206 |
| 182 // a path renderer may be holding onto resources that | 207 // a path renderer may be holding onto resources that |
| 183 // are now unusable | 208 // are now unusable |
| 184 SkSafeSetNull(fPathRendererChain); | 209 SkSafeSetNull(fPathRendererChain); |
| 185 SkSafeSetNull(fSoftwarePathRenderer); | 210 SkSafeSetNull(fSoftwarePathRenderer); |
| 186 | 211 |
| 187 SkDELETE(fDrawBuffer); | 212 fDrawingMgr.abandon(); |
| 188 fDrawBuffer = NULL; | |
| 189 | 213 |
| 190 fBatchFontCache->freeAll(); | 214 fBatchFontCache->freeAll(); |
| 191 fLayerCache->freeAll(); | 215 fLayerCache->freeAll(); |
| 192 fTextBlobCache->freeAll(); | 216 fTextBlobCache->freeAll(); |
| 193 } | 217 } |
| 194 | 218 |
| 195 void GrContext::resetContext(uint32_t state) { | 219 void GrContext::resetContext(uint32_t state) { |
| 196 fGpu->markContextDirty(state); | 220 fGpu->markContextDirty(state); |
| 197 } | 221 } |
| 198 | 222 |
| 199 void GrContext::freeGpuResources() { | 223 void GrContext::freeGpuResources() { |
| 200 this->flush(); | 224 this->flush(); |
| 201 | 225 |
| 202 if (fDrawBuffer) { | 226 fDrawingMgr.purgeResources(); |
| 203 fDrawBuffer->purgeResources(); | |
| 204 } | |
| 205 | 227 |
| 206 fBatchFontCache->freeAll(); | 228 fBatchFontCache->freeAll(); |
| 207 fLayerCache->freeAll(); | 229 fLayerCache->freeAll(); |
| 208 // a path renderer may be holding onto resources | 230 // a path renderer may be holding onto resources |
| 209 SkSafeSetNull(fPathRendererChain); | 231 SkSafeSetNull(fPathRendererChain); |
| 210 SkSafeSetNull(fSoftwarePathRenderer); | 232 SkSafeSetNull(fSoftwarePathRenderer); |
| 211 | 233 |
| 212 fResourceCache->purgeAllUnlocked(); | 234 fResourceCache->purgeAllUnlocked(); |
| 213 } | 235 } |
| 214 | 236 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 231 if (sb) { | 253 if (sb) { |
| 232 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyPr
operties); | 254 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyPr
operties); |
| 233 } | 255 } |
| 234 } | 256 } |
| 235 | 257 |
| 236 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDi
stanceFieldFonts); | 258 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDi
stanceFieldFonts); |
| 237 } | 259 } |
| 238 | 260 |
| 239 //////////////////////////////////////////////////////////////////////////////// | 261 //////////////////////////////////////////////////////////////////////////////// |
| 240 | 262 |
| 263 bool GrContext::shaderDerivativeSupport() const { |
| 264 return fGpu->caps()->shaderCaps()->shaderDerivativeSupport(); |
| 265 } |
| 266 |
| 241 bool GrContext::isConfigTexturable(GrPixelConfig config) const { | 267 bool GrContext::isConfigTexturable(GrPixelConfig config) const { |
| 242 return fGpu->caps()->isConfigTexturable(config); | 268 return fGpu->caps()->isConfigTexturable(config); |
| 243 } | 269 } |
| 244 | 270 |
| 245 bool GrContext::npotTextureTileSupport() const { | 271 bool GrContext::npotTextureTileSupport() const { |
| 246 return fGpu->caps()->npotTextureTileSupport(); | 272 return fGpu->caps()->npotTextureTileSupport(); |
| 247 } | 273 } |
| 248 | 274 |
| 249 void GrContext::OverBudgetCB(void* data) { | 275 void GrContext::OverBudgetCB(void* data) { |
| 250 SkASSERT(data); | 276 SkASSERT(data); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 271 } | 297 } |
| 272 | 298 |
| 273 int GrContext::getMaxRenderTargetSize() const { | 299 int GrContext::getMaxRenderTargetSize() const { |
| 274 return fGpu->caps()->maxRenderTargetSize(); | 300 return fGpu->caps()->maxRenderTargetSize(); |
| 275 } | 301 } |
| 276 | 302 |
| 277 int GrContext::getMaxSampleCount() const { | 303 int GrContext::getMaxSampleCount() const { |
| 278 return fGpu->caps()->maxSampleCount(); | 304 return fGpu->caps()->maxSampleCount(); |
| 279 } | 305 } |
| 280 | 306 |
| 281 /////////////////////////////////////////////////////////////////////////////// | |
| 282 | |
| 283 void GrContext::clear(const SkIRect* rect, | |
| 284 const GrColor color, | |
| 285 bool canIgnoreRect, | |
| 286 GrRenderTarget* renderTarget) { | |
| 287 RETURN_IF_ABANDONED | |
| 288 ASSERT_OWNED_RESOURCE(renderTarget); | |
| 289 SkASSERT(renderTarget); | |
| 290 | |
| 291 AutoCheckFlush acf(this); | |
| 292 GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this); | |
| 293 GrDrawTarget* target = this->prepareToDraw(); | |
| 294 if (NULL == target) { | |
| 295 return; | |
| 296 } | |
| 297 target->clear(rect, color, canIgnoreRect, renderTarget); | |
| 298 } | |
| 299 | |
| 300 void GrContext::drawPaint(GrRenderTarget* rt, | |
| 301 const GrClip& clip, | |
| 302 const GrPaint& origPaint, | |
| 303 const SkMatrix& viewMatrix) { | |
| 304 RETURN_IF_ABANDONED | |
| 305 // set rect to be big enough to fill the space, but not super-huge, so we | |
| 306 // don't overflow fixed-point implementations | |
| 307 SkRect r; | |
| 308 r.setLTRB(0, 0, | |
| 309 SkIntToScalar(rt->width()), | |
| 310 SkIntToScalar(rt->height())); | |
| 311 SkTCopyOnFirstWrite<GrPaint> paint(origPaint); | |
| 312 | |
| 313 // by definition this fills the entire clip, no need for AA | |
| 314 if (paint->isAntiAlias()) { | |
| 315 paint.writable()->setAntiAlias(false); | |
| 316 } | |
| 317 | |
| 318 bool isPerspective = viewMatrix.hasPerspective(); | |
| 319 | |
| 320 // We attempt to map r by the inverse matrix and draw that. mapRect will | |
| 321 // map the four corners and bound them with a new rect. This will not | |
| 322 // produce a correct result for some perspective matrices. | |
| 323 if (!isPerspective) { | |
| 324 SkMatrix inverse; | |
| 325 if (!viewMatrix.invert(&inverse)) { | |
| 326 SkDebugf("Could not invert matrix\n"); | |
| 327 return; | |
| 328 } | |
| 329 inverse.mapRect(&r); | |
| 330 this->drawRect(rt, clip, *paint, viewMatrix, r); | |
| 331 } else { | |
| 332 SkMatrix localMatrix; | |
| 333 if (!viewMatrix.invert(&localMatrix)) { | |
| 334 SkDebugf("Could not invert matrix\n"); | |
| 335 return; | |
| 336 } | |
| 337 | |
| 338 AutoCheckFlush acf(this); | |
| 339 GrPipelineBuilder pipelineBuilder; | |
| 340 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, p
aint, &acf); | |
| 341 if (NULL == target) { | |
| 342 return; | |
| 343 } | |
| 344 | |
| 345 GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target); | |
| 346 target->drawRect(&pipelineBuilder, | |
| 347 paint->getColor(), | |
| 348 SkMatrix::I(), | |
| 349 r, | |
| 350 NULL, | |
| 351 &localMatrix); | |
| 352 } | |
| 353 } | |
| 354 | |
| 355 //////////////////////////////////////////////////////////////////////////////// | |
| 356 | |
| 357 static inline bool is_irect(const SkRect& r) { | |
| 358 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) && | |
| 359 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom); | |
| 360 } | |
| 361 | |
| 362 static bool apply_aa_to_rect(GrDrawTarget* target, | |
| 363 GrPipelineBuilder* pipelineBuilder, | |
| 364 SkRect* devBoundRect, | |
| 365 const SkRect& rect, | |
| 366 SkScalar strokeWidth, | |
| 367 const SkMatrix& combinedMatrix, | |
| 368 GrColor color) { | |
| 369 if (pipelineBuilder->getRenderTarget()->isMultisampled()) { | |
| 370 return false; | |
| 371 } | |
| 372 | |
| 373 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) | |
| 374 if (strokeWidth >= 0) { | |
| 375 #endif | |
| 376 if (!combinedMatrix.preservesAxisAlignment()) { | |
| 377 return false; | |
| 378 } | |
| 379 | |
| 380 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) | |
| 381 } else { | |
| 382 if (!combinedMatrix.preservesRightAngles()) { | |
| 383 return false; | |
| 384 } | |
| 385 } | |
| 386 #endif | |
| 387 | |
| 388 combinedMatrix.mapRect(devBoundRect, rect); | |
| 389 if (!combinedMatrix.rectStaysRect()) { | |
| 390 return true; | |
| 391 } | |
| 392 | |
| 393 if (strokeWidth < 0) { | |
| 394 return !is_irect(*devBoundRect); | |
| 395 } | |
| 396 | |
| 397 return true; | |
| 398 } | |
| 399 | |
| 400 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& po
int) { | |
| 401 return point.fX >= rect.fLeft && point.fX <= rect.fRight && | |
| 402 point.fY >= rect.fTop && point.fY <= rect.fBottom; | |
| 403 } | |
| 404 | |
| 405 class StrokeRectBatch : public GrBatch { | |
| 406 public: | |
| 407 struct Geometry { | |
| 408 GrColor fColor; | |
| 409 SkMatrix fViewMatrix; | |
| 410 SkRect fRect; | |
| 411 SkScalar fStrokeWidth; | |
| 412 }; | |
| 413 | |
| 414 static GrBatch* Create(const Geometry& geometry, bool snapToPixelCenters) { | |
| 415 return SkNEW_ARGS(StrokeRectBatch, (geometry, snapToPixelCenters)); | |
| 416 } | |
| 417 | |
| 418 const char* name() const override { return "StrokeRectBatch"; } | |
| 419 | |
| 420 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | |
| 421 // When this is called on a batch, there is only one geometry bundle | |
| 422 out->setKnownFourComponents(fGeoData[0].fColor); | |
| 423 } | |
| 424 | |
| 425 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | |
| 426 out->setKnownSingleComponent(0xff); | |
| 427 } | |
| 428 | |
| 429 void initBatchTracker(const GrPipelineInfo& init) override { | |
| 430 // Handle any color overrides | |
| 431 if (init.fColorIgnored) { | |
| 432 fGeoData[0].fColor = GrColor_ILLEGAL; | |
| 433 } else if (GrColor_ILLEGAL != init.fOverrideColor) { | |
| 434 fGeoData[0].fColor = init.fOverrideColor; | |
| 435 } | |
| 436 | |
| 437 // setup batch properties | |
| 438 fBatch.fColorIgnored = init.fColorIgnored; | |
| 439 fBatch.fColor = fGeoData[0].fColor; | |
| 440 fBatch.fUsesLocalCoords = init.fUsesLocalCoords; | |
| 441 fBatch.fCoverageIgnored = init.fCoverageIgnored; | |
| 442 } | |
| 443 | |
| 444 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override { | |
| 445 SkAutoTUnref<const GrGeometryProcessor> gp( | |
| 446 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPositi
on_GPType, | |
| 447 this->color(), | |
| 448 this->usesLocalCoords(), | |
| 449 this->coverageIgnored(), | |
| 450 this->viewMatrix(), | |
| 451 SkMatrix::I())); | |
| 452 | |
| 453 batchTarget->initDraw(gp, pipeline); | |
| 454 | |
| 455 size_t vertexStride = gp->getVertexStride(); | |
| 456 | |
| 457 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); | |
| 458 | |
| 459 Geometry& args = fGeoData[0]; | |
| 460 | |
| 461 int vertexCount = kVertsPerHairlineRect; | |
| 462 if (args.fStrokeWidth > 0) { | |
| 463 vertexCount = kVertsPerStrokeRect; | |
| 464 } | |
| 465 | |
| 466 const GrVertexBuffer* vertexBuffer; | |
| 467 int firstVertex; | |
| 468 | |
| 469 void* verts = batchTarget->makeVertSpace(vertexStride, vertexCount, | |
| 470 &vertexBuffer, &firstVertex); | |
| 471 | |
| 472 if (!verts) { | |
| 473 SkDebugf("Could not allocate vertices\n"); | |
| 474 return; | |
| 475 } | |
| 476 | |
| 477 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); | |
| 478 | |
| 479 GrPrimitiveType primType; | |
| 480 | |
| 481 if (args.fStrokeWidth > 0) {; | |
| 482 primType = kTriangleStrip_GrPrimitiveType; | |
| 483 args.fRect.sort(); | |
| 484 this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth); | |
| 485 } else { | |
| 486 // hairline | |
| 487 primType = kLineStrip_GrPrimitiveType; | |
| 488 vertex[0].set(args.fRect.fLeft, args.fRect.fTop); | |
| 489 vertex[1].set(args.fRect.fRight, args.fRect.fTop); | |
| 490 vertex[2].set(args.fRect.fRight, args.fRect.fBottom); | |
| 491 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom); | |
| 492 vertex[4].set(args.fRect.fLeft, args.fRect.fTop); | |
| 493 } | |
| 494 | |
| 495 GrVertices vertices; | |
| 496 vertices.init(primType, vertexBuffer, firstVertex, vertexCount); | |
| 497 batchTarget->draw(vertices); | |
| 498 } | |
| 499 | |
| 500 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
| 501 | |
| 502 private: | |
| 503 StrokeRectBatch(const Geometry& geometry, bool snapToPixelCenters) { | |
| 504 this->initClassID<StrokeRectBatch>(); | |
| 505 | |
| 506 fBatch.fHairline = geometry.fStrokeWidth == 0; | |
| 507 | |
| 508 fGeoData.push_back(geometry); | |
| 509 | |
| 510 // setup bounds | |
| 511 fBounds = geometry.fRect; | |
| 512 SkScalar rad = SkScalarHalf(geometry.fStrokeWidth); | |
| 513 fBounds.outset(rad, rad); | |
| 514 geometry.fViewMatrix.mapRect(&fBounds); | |
| 515 | |
| 516 // If our caller snaps to pixel centers then we have to round out the bo
unds | |
| 517 if (snapToPixelCenters) { | |
| 518 fBounds.roundOut(); | |
| 519 } | |
| 520 } | |
| 521 | |
| 522 /* create a triangle strip that strokes the specified rect. There are 8 | |
| 523 unique vertices, but we repeat the last 2 to close up. Alternatively we | |
| 524 could use an indices array, and then only send 8 verts, but not sure that | |
| 525 would be faster. | |
| 526 */ | |
| 527 void setStrokeRectStrip(SkPoint verts[10], const SkRect& rect, SkScalar widt
h) { | |
| 528 const SkScalar rad = SkScalarHalf(width); | |
| 529 // TODO we should be able to enable this assert, but we'd have to filter
these draws | |
| 530 // this is a bug | |
| 531 //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2); | |
| 532 | |
| 533 verts[0].set(rect.fLeft + rad, rect.fTop + rad); | |
| 534 verts[1].set(rect.fLeft - rad, rect.fTop - rad); | |
| 535 verts[2].set(rect.fRight - rad, rect.fTop + rad); | |
| 536 verts[3].set(rect.fRight + rad, rect.fTop - rad); | |
| 537 verts[4].set(rect.fRight - rad, rect.fBottom - rad); | |
| 538 verts[5].set(rect.fRight + rad, rect.fBottom + rad); | |
| 539 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); | |
| 540 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); | |
| 541 verts[8] = verts[0]; | |
| 542 verts[9] = verts[1]; | |
| 543 } | |
| 544 | |
| 545 | |
| 546 GrColor color() const { return fBatch.fColor; } | |
| 547 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
| 548 bool colorIgnored() const { return fBatch.fColorIgnored; } | |
| 549 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
| 550 bool hairline() const { return fBatch.fHairline; } | |
| 551 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
| 552 | |
| 553 bool onCombineIfPossible(GrBatch* t) override { | |
| 554 // StrokeRectBatch* that = t->cast<StrokeRectBatch>(); | |
| 555 | |
| 556 // NonAA stroke rects cannot batch right now | |
| 557 // TODO make these batchable | |
| 558 return false; | |
| 559 } | |
| 560 | |
| 561 struct BatchTracker { | |
| 562 GrColor fColor; | |
| 563 bool fUsesLocalCoords; | |
| 564 bool fColorIgnored; | |
| 565 bool fCoverageIgnored; | |
| 566 bool fHairline; | |
| 567 }; | |
| 568 | |
| 569 const static int kVertsPerHairlineRect = 5; | |
| 570 const static int kVertsPerStrokeRect = 10; | |
| 571 | |
| 572 BatchTracker fBatch; | |
| 573 SkSTArray<1, Geometry, true> fGeoData; | |
| 574 }; | |
| 575 | |
| 576 void GrContext::drawRect(GrRenderTarget* rt, | |
| 577 const GrClip& clip, | |
| 578 const GrPaint& paint, | |
| 579 const SkMatrix& viewMatrix, | |
| 580 const SkRect& rect, | |
| 581 const GrStrokeInfo* strokeInfo) { | |
| 582 RETURN_IF_ABANDONED | |
| 583 if (strokeInfo && strokeInfo->isDashed()) { | |
| 584 SkPath path; | |
| 585 path.setIsVolatile(true); | |
| 586 path.addRect(rect); | |
| 587 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo); | |
| 588 return; | |
| 589 } | |
| 590 | |
| 591 AutoCheckFlush acf(this); | |
| 592 GrPipelineBuilder pipelineBuilder; | |
| 593 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
| 594 if (NULL == target) { | |
| 595 return; | |
| 596 } | |
| 597 | |
| 598 GR_CREATE_TRACE_MARKER("GrContext::drawRect", target); | |
| 599 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth(); | |
| 600 | |
| 601 // Check if this is a full RT draw and can be replaced with a clear. We don'
t bother checking | |
| 602 // cases where the RT is fully inside a stroke. | |
| 603 if (width < 0) { | |
| 604 SkRect rtRect; | |
| 605 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect); | |
| 606 SkRect clipSpaceRTRect = rtRect; | |
| 607 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType(); | |
| 608 if (checkClip) { | |
| 609 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX), | |
| 610 SkIntToScalar(clip.origin().fY)); | |
| 611 } | |
| 612 // Does the clip contain the entire RT? | |
| 613 if (!checkClip || clip.quickContains(clipSpaceRTRect)) { | |
| 614 SkMatrix invM; | |
| 615 if (!viewMatrix.invert(&invM)) { | |
| 616 return; | |
| 617 } | |
| 618 // Does the rect bound the RT? | |
| 619 SkPoint srcSpaceRTQuad[4]; | |
| 620 invM.mapRectToQuad(srcSpaceRTQuad, rtRect); | |
| 621 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) && | |
| 622 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) && | |
| 623 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) && | |
| 624 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) { | |
| 625 // Will it blend? | |
| 626 GrColor clearColor; | |
| 627 if (paint.isOpaqueAndConstantColor(&clearColor)) { | |
| 628 target->clear(NULL, clearColor, true, rt); | |
| 629 return; | |
| 630 } | |
| 631 } | |
| 632 } | |
| 633 } | |
| 634 | |
| 635 GrColor color = paint.getColor(); | |
| 636 SkRect devBoundRect; | |
| 637 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isM
ultisampled(); | |
| 638 bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRe
ct, rect, width, | |
| 639 viewMatrix, color); | |
| 640 | |
| 641 if (doAA) { | |
| 642 if (width >= 0) { | |
| 643 fAARectRenderer->strokeAARect(target, | |
| 644 &pipelineBuilder, | |
| 645 color, | |
| 646 viewMatrix, | |
| 647 rect, | |
| 648 devBoundRect, | |
| 649 *strokeInfo); | |
| 650 } else { | |
| 651 // filled AA rect | |
| 652 fAARectRenderer->fillAARect(target, | |
| 653 &pipelineBuilder, | |
| 654 color, | |
| 655 viewMatrix, | |
| 656 rect, | |
| 657 devBoundRect); | |
| 658 } | |
| 659 return; | |
| 660 } | |
| 661 | |
| 662 if (width >= 0) { | |
| 663 StrokeRectBatch::Geometry geometry; | |
| 664 geometry.fViewMatrix = viewMatrix; | |
| 665 geometry.fColor = color; | |
| 666 geometry.fRect = rect; | |
| 667 geometry.fStrokeWidth = width; | |
| 668 | |
| 669 // Non-AA hairlines are snapped to pixel centers to make which pixels ar
e hit deterministic | |
| 670 bool snapToPixelCenters = (0 == width && !rt->isMultisampled()); | |
| 671 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixe
lCenters)); | |
| 672 | |
| 673 // Depending on sub-pixel coordinates and the particular GPU, we may los
e a corner of | |
| 674 // hairline rects. We jam all the vertices to pixel centers to avoid thi
s, but not when MSAA | |
| 675 // is enabled because it can cause ugly artifacts. | |
| 676 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_
Flag, | |
| 677 snapToPixelCenters); | |
| 678 target->drawBatch(&pipelineBuilder, batch); | |
| 679 } else { | |
| 680 // filled BW rect | |
| 681 target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect); | |
| 682 } | |
| 683 } | |
| 684 | |
| 685 void GrContext::drawNonAARectToRect(GrRenderTarget* rt, | |
| 686 const GrClip& clip, | |
| 687 const GrPaint& paint, | |
| 688 const SkMatrix& viewMatrix, | |
| 689 const SkRect& rectToDraw, | |
| 690 const SkRect& localRect, | |
| 691 const SkMatrix* localMatrix) { | |
| 692 RETURN_IF_ABANDONED | |
| 693 AutoCheckFlush acf(this); | |
| 694 GrPipelineBuilder pipelineBuilder; | |
| 695 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
| 696 if (NULL == target) { | |
| 697 return; | |
| 698 } | |
| 699 | |
| 700 GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target); | |
| 701 | |
| 702 target->drawRect(&pipelineBuilder, | |
| 703 paint.getColor(), | |
| 704 viewMatrix, | |
| 705 rectToDraw, | |
| 706 &localRect, | |
| 707 localMatrix); | |
| 708 } | |
| 709 | |
| 710 static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords, | |
| 711 bool hasColors, | |
| 712 int* colorOffset, | |
| 713 int* texOffset, | |
| 714 GrColor color, | |
| 715 const SkMatrix& viewMatr
ix, | |
| 716 bool coverageIgnored) { | |
| 717 *texOffset = -1; | |
| 718 *colorOffset = -1; | |
| 719 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType; | |
| 720 if (hasLocalCoords && hasColors) { | |
| 721 *colorOffset = sizeof(SkPoint); | |
| 722 *texOffset = sizeof(SkPoint) + sizeof(GrColor); | |
| 723 flags |= GrDefaultGeoProcFactory::kColor_GPType | | |
| 724 GrDefaultGeoProcFactory::kLocalCoord_GPType; | |
| 725 } else if (hasLocalCoords) { | |
| 726 *texOffset = sizeof(SkPoint); | |
| 727 flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType; | |
| 728 } else if (hasColors) { | |
| 729 *colorOffset = sizeof(SkPoint); | |
| 730 flags |= GrDefaultGeoProcFactory::kColor_GPType; | |
| 731 } | |
| 732 return GrDefaultGeoProcFactory::Create(flags, color, hasLocalCoords, coverag
eIgnored, | |
| 733 viewMatrix, SkMatrix::I()); | |
| 734 } | |
| 735 | |
| 736 class DrawVerticesBatch : public GrBatch { | |
| 737 public: | |
| 738 struct Geometry { | |
| 739 GrColor fColor; | |
| 740 SkTDArray<SkPoint> fPositions; | |
| 741 SkTDArray<uint16_t> fIndices; | |
| 742 SkTDArray<GrColor> fColors; | |
| 743 SkTDArray<SkPoint> fLocalCoords; | |
| 744 }; | |
| 745 | |
| 746 static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveTy
pe, | |
| 747 const SkMatrix& viewMatrix, | |
| 748 const SkPoint* positions, int vertexCount, | |
| 749 const uint16_t* indices, int indexCount, | |
| 750 const GrColor* colors, const SkPoint* localCoords, | |
| 751 const SkRect& bounds) { | |
| 752 return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatri
x, positions, | |
| 753 vertexCount, indices, indexCount,
colors, | |
| 754 localCoords, bounds)); | |
| 755 } | |
| 756 | |
| 757 const char* name() const override { return "DrawVerticesBatch"; } | |
| 758 | |
| 759 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | |
| 760 // When this is called on a batch, there is only one geometry bundle | |
| 761 if (this->hasColors()) { | |
| 762 out->setUnknownFourComponents(); | |
| 763 } else { | |
| 764 out->setKnownFourComponents(fGeoData[0].fColor); | |
| 765 } | |
| 766 } | |
| 767 | |
| 768 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | |
| 769 out->setKnownSingleComponent(0xff); | |
| 770 } | |
| 771 | |
| 772 void initBatchTracker(const GrPipelineInfo& init) override { | |
| 773 // Handle any color overrides | |
| 774 if (init.fColorIgnored) { | |
| 775 fGeoData[0].fColor = GrColor_ILLEGAL; | |
| 776 } else if (GrColor_ILLEGAL != init.fOverrideColor) { | |
| 777 fGeoData[0].fColor = init.fOverrideColor; | |
| 778 } | |
| 779 | |
| 780 // setup batch properties | |
| 781 fBatch.fColorIgnored = init.fColorIgnored; | |
| 782 fBatch.fColor = fGeoData[0].fColor; | |
| 783 fBatch.fUsesLocalCoords = init.fUsesLocalCoords; | |
| 784 fBatch.fCoverageIgnored = init.fCoverageIgnored; | |
| 785 } | |
| 786 | |
| 787 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override { | |
| 788 int colorOffset = -1, texOffset = -1; | |
| 789 SkAutoTUnref<const GrGeometryProcessor> gp( | |
| 790 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(),
&colorOffset, | |
| 791 &texOffset, this->color(), this->viewMatri
x(), | |
| 792 this->coverageIgnored())); | |
| 793 | |
| 794 batchTarget->initDraw(gp, pipeline); | |
| 795 | |
| 796 size_t vertexStride = gp->getVertexStride(); | |
| 797 | |
| 798 SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? siz
eof(SkPoint) : 0) | |
| 799 + (this->hasColors() ? sizeof(G
rColor) : 0)); | |
| 800 | |
| 801 int instanceCount = fGeoData.count(); | |
| 802 | |
| 803 const GrVertexBuffer* vertexBuffer; | |
| 804 int firstVertex; | |
| 805 | |
| 806 void* verts = batchTarget->makeVertSpace(vertexStride, this->vertexCount
(), | |
| 807 &vertexBuffer, &firstVertex); | |
| 808 | |
| 809 if (!verts) { | |
| 810 SkDebugf("Could not allocate vertices\n"); | |
| 811 return; | |
| 812 } | |
| 813 | |
| 814 const GrIndexBuffer* indexBuffer = NULL; | |
| 815 int firstIndex = 0; | |
| 816 | |
| 817 uint16_t* indices = NULL; | |
| 818 if (this->hasIndices()) { | |
| 819 indices = batchTarget->makeIndexSpace(this->indexCount(), &indexBuff
er, &firstIndex); | |
| 820 | |
| 821 if (!indices) { | |
| 822 SkDebugf("Could not allocate indices\n"); | |
| 823 return; | |
| 824 } | |
| 825 } | |
| 826 | |
| 827 int indexOffset = 0; | |
| 828 int vertexOffset = 0; | |
| 829 for (int i = 0; i < instanceCount; i++) { | |
| 830 const Geometry& args = fGeoData[i]; | |
| 831 | |
| 832 // TODO we can actually cache this interleaved and then just memcopy | |
| 833 if (this->hasIndices()) { | |
| 834 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) { | |
| 835 *(indices + indexOffset) = args.fIndices[j] + vertexOffset; | |
| 836 } | |
| 837 } | |
| 838 | |
| 839 for (int j = 0; j < args.fPositions.count(); ++j) { | |
| 840 *((SkPoint*)verts) = args.fPositions[j]; | |
| 841 if (this->hasColors()) { | |
| 842 *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j]
; | |
| 843 } | |
| 844 if (this->hasLocalCoords()) { | |
| 845 *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords
[j]; | |
| 846 } | |
| 847 verts = (void*)((intptr_t)verts + vertexStride); | |
| 848 vertexOffset++; | |
| 849 } | |
| 850 } | |
| 851 | |
| 852 GrVertices vertices; | |
| 853 if (this->hasIndices()) { | |
| 854 vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffe
r, firstVertex, | |
| 855 firstIndex, this->vertexCount(), this->indexCou
nt()); | |
| 856 | |
| 857 } else { | |
| 858 vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this
->vertexCount()); | |
| 859 } | |
| 860 batchTarget->draw(vertices); | |
| 861 } | |
| 862 | |
| 863 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
| 864 | |
| 865 private: | |
| 866 DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType, | |
| 867 const SkMatrix& viewMatrix, | |
| 868 const SkPoint* positions, int vertexCount, | |
| 869 const uint16_t* indices, int indexCount, | |
| 870 const GrColor* colors, const SkPoint* localCoords, const S
kRect& bounds) { | |
| 871 this->initClassID<DrawVerticesBatch>(); | |
| 872 SkASSERT(positions); | |
| 873 | |
| 874 fBatch.fViewMatrix = viewMatrix; | |
| 875 Geometry& installedGeo = fGeoData.push_back(geometry); | |
| 876 | |
| 877 installedGeo.fPositions.append(vertexCount, positions); | |
| 878 if (indices) { | |
| 879 installedGeo.fIndices.append(indexCount, indices); | |
| 880 fBatch.fHasIndices = true; | |
| 881 } else { | |
| 882 fBatch.fHasIndices = false; | |
| 883 } | |
| 884 | |
| 885 if (colors) { | |
| 886 installedGeo.fColors.append(vertexCount, colors); | |
| 887 fBatch.fHasColors = true; | |
| 888 } else { | |
| 889 fBatch.fHasColors = false; | |
| 890 } | |
| 891 | |
| 892 if (localCoords) { | |
| 893 installedGeo.fLocalCoords.append(vertexCount, localCoords); | |
| 894 fBatch.fHasLocalCoords = true; | |
| 895 } else { | |
| 896 fBatch.fHasLocalCoords = false; | |
| 897 } | |
| 898 fBatch.fVertexCount = vertexCount; | |
| 899 fBatch.fIndexCount = indexCount; | |
| 900 fBatch.fPrimitiveType = primitiveType; | |
| 901 | |
| 902 this->setBounds(bounds); | |
| 903 } | |
| 904 | |
| 905 GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; } | |
| 906 bool batchablePrimitiveType() const { | |
| 907 return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType || | |
| 908 kLines_GrPrimitiveType == fBatch.fPrimitiveType || | |
| 909 kPoints_GrPrimitiveType == fBatch.fPrimitiveType; | |
| 910 } | |
| 911 GrColor color() const { return fBatch.fColor; } | |
| 912 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
| 913 bool colorIgnored() const { return fBatch.fColorIgnored; } | |
| 914 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } | |
| 915 bool hasColors() const { return fBatch.fHasColors; } | |
| 916 bool hasIndices() const { return fBatch.fHasIndices; } | |
| 917 bool hasLocalCoords() const { return fBatch.fHasLocalCoords; } | |
| 918 int vertexCount() const { return fBatch.fVertexCount; } | |
| 919 int indexCount() const { return fBatch.fIndexCount; } | |
| 920 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
| 921 | |
| 922 bool onCombineIfPossible(GrBatch* t) override { | |
| 923 DrawVerticesBatch* that = t->cast<DrawVerticesBatch>(); | |
| 924 | |
| 925 if (!this->batchablePrimitiveType() || this->primitiveType() != that->pr
imitiveType()) { | |
| 926 return false; | |
| 927 } | |
| 928 | |
| 929 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords()); | |
| 930 | |
| 931 // We currently use a uniform viewmatrix for this batch | |
| 932 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { | |
| 933 return false; | |
| 934 } | |
| 935 | |
| 936 if (this->hasColors() != that->hasColors()) { | |
| 937 return false; | |
| 938 } | |
| 939 | |
| 940 if (this->hasIndices() != that->hasIndices()) { | |
| 941 return false; | |
| 942 } | |
| 943 | |
| 944 if (this->hasLocalCoords() != that->hasLocalCoords()) { | |
| 945 return false; | |
| 946 } | |
| 947 | |
| 948 if (!this->hasColors() && this->color() != that->color()) { | |
| 949 return false; | |
| 950 } | |
| 951 | |
| 952 if (this->color() != that->color()) { | |
| 953 fBatch.fColor = GrColor_ILLEGAL; | |
| 954 } | |
| 955 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin())
; | |
| 956 fBatch.fVertexCount += that->vertexCount(); | |
| 957 fBatch.fIndexCount += that->indexCount(); | |
| 958 | |
| 959 this->joinBounds(that->bounds()); | |
| 960 return true; | |
| 961 } | |
| 962 | |
| 963 struct BatchTracker { | |
| 964 GrPrimitiveType fPrimitiveType; | |
| 965 SkMatrix fViewMatrix; | |
| 966 GrColor fColor; | |
| 967 bool fUsesLocalCoords; | |
| 968 bool fColorIgnored; | |
| 969 bool fCoverageIgnored; | |
| 970 bool fHasColors; | |
| 971 bool fHasIndices; | |
| 972 bool fHasLocalCoords; | |
| 973 int fVertexCount; | |
| 974 int fIndexCount; | |
| 975 }; | |
| 976 | |
| 977 BatchTracker fBatch; | |
| 978 SkSTArray<1, Geometry, true> fGeoData; | |
| 979 }; | |
| 980 | |
| 981 void GrContext::drawVertices(GrRenderTarget* rt, | |
| 982 const GrClip& clip, | |
| 983 const GrPaint& paint, | |
| 984 const SkMatrix& viewMatrix, | |
| 985 GrPrimitiveType primitiveType, | |
| 986 int vertexCount, | |
| 987 const SkPoint positions[], | |
| 988 const SkPoint texCoords[], | |
| 989 const GrColor colors[], | |
| 990 const uint16_t indices[], | |
| 991 int indexCount) { | |
| 992 RETURN_IF_ABANDONED | |
| 993 AutoCheckFlush acf(this); | |
| 994 GrPipelineBuilder pipelineBuilder; | |
| 995 | |
| 996 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
| 997 if (NULL == target) { | |
| 998 return; | |
| 999 } | |
| 1000 | |
| 1001 GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target); | |
| 1002 | |
| 1003 // TODO clients should give us bounds | |
| 1004 SkRect bounds; | |
| 1005 if (!bounds.setBoundsCheck(positions, vertexCount)) { | |
| 1006 SkDebugf("drawVertices call empty bounds\n"); | |
| 1007 return; | |
| 1008 } | |
| 1009 | |
| 1010 viewMatrix.mapRect(&bounds); | |
| 1011 | |
| 1012 // If we don't have AA then we outset for a half pixel in each direction to
account for | |
| 1013 // snapping | |
| 1014 if (!paint.isAntiAlias()) { | |
| 1015 bounds.outset(0.5f, 0.5f); | |
| 1016 } | |
| 1017 | |
| 1018 DrawVerticesBatch::Geometry geometry; | |
| 1019 geometry.fColor = paint.getColor(); | |
| 1020 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveTyp
e, viewMatrix, | |
| 1021 positions, vertexCount
, indices, | |
| 1022 indexCount, colors, te
xCoords, | |
| 1023 bounds)); | |
| 1024 | |
| 1025 target->drawBatch(&pipelineBuilder, batch); | |
| 1026 } | |
| 1027 | |
| 1028 /////////////////////////////////////////////////////////////////////////////// | |
| 1029 | |
| 1030 void GrContext::drawRRect(GrRenderTarget*rt, | |
| 1031 const GrClip& clip, | |
| 1032 const GrPaint& paint, | |
| 1033 const SkMatrix& viewMatrix, | |
| 1034 const SkRRect& rrect, | |
| 1035 const GrStrokeInfo& strokeInfo) { | |
| 1036 RETURN_IF_ABANDONED | |
| 1037 if (rrect.isEmpty()) { | |
| 1038 return; | |
| 1039 } | |
| 1040 | |
| 1041 if (strokeInfo.isDashed()) { | |
| 1042 SkPath path; | |
| 1043 path.setIsVolatile(true); | |
| 1044 path.addRRect(rrect); | |
| 1045 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); | |
| 1046 return; | |
| 1047 } | |
| 1048 | |
| 1049 AutoCheckFlush acf(this); | |
| 1050 GrPipelineBuilder pipelineBuilder; | |
| 1051 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
| 1052 if (NULL == target) { | |
| 1053 return; | |
| 1054 } | |
| 1055 | |
| 1056 GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target); | |
| 1057 | |
| 1058 GrColor color = paint.getColor(); | |
| 1059 if (!fOvalRenderer->drawRRect(target, | |
| 1060 &pipelineBuilder, | |
| 1061 color, | |
| 1062 viewMatrix, | |
| 1063 paint.isAntiAlias(), | |
| 1064 rrect, | |
| 1065 strokeInfo)) { | |
| 1066 SkPath path; | |
| 1067 path.setIsVolatile(true); | |
| 1068 path.addRRect(rrect); | |
| 1069 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain
t.isAntiAlias(), | |
| 1070 path, strokeInfo); | |
| 1071 } | |
| 1072 } | |
| 1073 | |
| 1074 /////////////////////////////////////////////////////////////////////////////// | |
| 1075 | |
| 1076 void GrContext::drawDRRect(GrRenderTarget* rt, | |
| 1077 const GrClip& clip, | |
| 1078 const GrPaint& paint, | |
| 1079 const SkMatrix& viewMatrix, | |
| 1080 const SkRRect& outer, | |
| 1081 const SkRRect& inner) { | |
| 1082 RETURN_IF_ABANDONED | |
| 1083 if (outer.isEmpty()) { | |
| 1084 return; | |
| 1085 } | |
| 1086 | |
| 1087 AutoCheckFlush acf(this); | |
| 1088 GrPipelineBuilder pipelineBuilder; | |
| 1089 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
| 1090 | |
| 1091 GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target); | |
| 1092 | |
| 1093 GrColor color = paint.getColor(); | |
| 1094 if (!fOvalRenderer->drawDRRect(target, | |
| 1095 &pipelineBuilder, | |
| 1096 color, | |
| 1097 viewMatrix, | |
| 1098 paint.isAntiAlias(), | |
| 1099 outer, | |
| 1100 inner)) { | |
| 1101 SkPath path; | |
| 1102 path.setIsVolatile(true); | |
| 1103 path.addRRect(inner); | |
| 1104 path.addRRect(outer); | |
| 1105 path.setFillType(SkPath::kEvenOdd_FillType); | |
| 1106 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle); | |
| 1107 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain
t.isAntiAlias(), | |
| 1108 path, fillRec); | |
| 1109 } | |
| 1110 } | |
| 1111 | |
| 1112 /////////////////////////////////////////////////////////////////////////////// | |
| 1113 | |
| 1114 void GrContext::drawOval(GrRenderTarget* rt, | |
| 1115 const GrClip& clip, | |
| 1116 const GrPaint& paint, | |
| 1117 const SkMatrix& viewMatrix, | |
| 1118 const SkRect& oval, | |
| 1119 const GrStrokeInfo& strokeInfo) { | |
| 1120 RETURN_IF_ABANDONED | |
| 1121 if (oval.isEmpty()) { | |
| 1122 return; | |
| 1123 } | |
| 1124 | |
| 1125 if (strokeInfo.isDashed()) { | |
| 1126 SkPath path; | |
| 1127 path.setIsVolatile(true); | |
| 1128 path.addOval(oval); | |
| 1129 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); | |
| 1130 return; | |
| 1131 } | |
| 1132 | |
| 1133 AutoCheckFlush acf(this); | |
| 1134 GrPipelineBuilder pipelineBuilder; | |
| 1135 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
| 1136 if (NULL == target) { | |
| 1137 return; | |
| 1138 } | |
| 1139 | |
| 1140 GR_CREATE_TRACE_MARKER("GrContext::drawOval", target); | |
| 1141 | |
| 1142 GrColor color = paint.getColor(); | |
| 1143 if (!fOvalRenderer->drawOval(target, | |
| 1144 &pipelineBuilder, | |
| 1145 color, | |
| 1146 viewMatrix, | |
| 1147 paint.isAntiAlias(), | |
| 1148 oval, | |
| 1149 strokeInfo)) { | |
| 1150 SkPath path; | |
| 1151 path.setIsVolatile(true); | |
| 1152 path.addOval(oval); | |
| 1153 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain
t.isAntiAlias(), | |
| 1154 path, strokeInfo); | |
| 1155 } | |
| 1156 } | |
| 1157 | |
| 1158 // Can 'path' be drawn as a pair of filled nested rectangles? | |
| 1159 static bool is_nested_rects(GrDrawTarget* target, | |
| 1160 GrPipelineBuilder* pipelineBuilder, | |
| 1161 GrColor color, | |
| 1162 const SkMatrix& viewMatrix, | |
| 1163 const SkPath& path, | |
| 1164 const SkStrokeRec& stroke, | |
| 1165 SkRect rects[2]) { | |
| 1166 SkASSERT(stroke.isFillStyle()); | |
| 1167 | |
| 1168 if (path.isInverseFillType()) { | |
| 1169 return false; | |
| 1170 } | |
| 1171 | |
| 1172 // TODO: this restriction could be lifted if we were willing to apply | |
| 1173 // the matrix to all the points individually rather than just to the rect | |
| 1174 if (!viewMatrix.preservesAxisAlignment()) { | |
| 1175 return false; | |
| 1176 } | |
| 1177 | |
| 1178 SkPath::Direction dirs[2]; | |
| 1179 if (!path.isNestedFillRects(rects, dirs)) { | |
| 1180 return false; | |
| 1181 } | |
| 1182 | |
| 1183 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) { | |
| 1184 // The two rects need to be wound opposite to each other | |
| 1185 return false; | |
| 1186 } | |
| 1187 | |
| 1188 // Right now, nested rects where the margin is not the same width | |
| 1189 // all around do not render correctly | |
| 1190 const SkScalar* outer = rects[0].asScalars(); | |
| 1191 const SkScalar* inner = rects[1].asScalars(); | |
| 1192 | |
| 1193 bool allEq = true; | |
| 1194 | |
| 1195 SkScalar margin = SkScalarAbs(outer[0] - inner[0]); | |
| 1196 bool allGoE1 = margin >= SK_Scalar1; | |
| 1197 | |
| 1198 for (int i = 1; i < 4; ++i) { | |
| 1199 SkScalar temp = SkScalarAbs(outer[i] - inner[i]); | |
| 1200 if (temp < SK_Scalar1) { | |
| 1201 allGoE1 = false; | |
| 1202 } | |
| 1203 if (!SkScalarNearlyEqual(margin, temp)) { | |
| 1204 allEq = false; | |
| 1205 } | |
| 1206 } | |
| 1207 | |
| 1208 return allEq || allGoE1; | |
| 1209 } | |
| 1210 | |
| 1211 void GrContext::drawPath(GrRenderTarget* rt, | |
| 1212 const GrClip& clip, | |
| 1213 const GrPaint& paint, | |
| 1214 const SkMatrix& viewMatrix, | |
| 1215 const SkPath& path, | |
| 1216 const GrStrokeInfo& strokeInfo) { | |
| 1217 RETURN_IF_ABANDONED | |
| 1218 if (path.isEmpty()) { | |
| 1219 if (path.isInverseFillType()) { | |
| 1220 this->drawPaint(rt, clip, paint, viewMatrix); | |
| 1221 } | |
| 1222 return; | |
| 1223 } | |
| 1224 | |
| 1225 GrColor color = paint.getColor(); | |
| 1226 | |
| 1227 // Note that internalDrawPath may sw-rasterize the path into a scratch textu
re. | |
| 1228 // Scratch textures can be recycled after they are returned to the texture | |
| 1229 // cache. This presents a potential hazard for buffered drawing. However, | |
| 1230 // the writePixels that uploads to the scratch will perform a flush so we're | |
| 1231 // OK. | |
| 1232 AutoCheckFlush acf(this); | |
| 1233 GrPipelineBuilder pipelineBuilder; | |
| 1234 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain
t, &acf); | |
| 1235 if (NULL == target) { | |
| 1236 return; | |
| 1237 } | |
| 1238 | |
| 1239 GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isC
onvex()); | |
| 1240 | |
| 1241 if (!strokeInfo.isDashed()) { | |
| 1242 bool useCoverageAA = paint.isAntiAlias() && | |
| 1243 !pipelineBuilder.getRenderTarget()->isMultisampled(); | |
| 1244 | |
| 1245 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) { | |
| 1246 // Concave AA paths are expensive - try to avoid them for special ca
ses | |
| 1247 SkRect rects[2]; | |
| 1248 | |
| 1249 if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, pat
h, strokeInfo, | |
| 1250 rects)) { | |
| 1251 fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, col
or, viewMatrix, | |
| 1252 rects); | |
| 1253 return; | |
| 1254 } | |
| 1255 } | |
| 1256 SkRect ovalRect; | |
| 1257 bool isOval = path.isOval(&ovalRect); | |
| 1258 | |
| 1259 if (isOval && !path.isInverseFillType()) { | |
| 1260 if (fOvalRenderer->drawOval(target, | |
| 1261 &pipelineBuilder, | |
| 1262 color, | |
| 1263 viewMatrix, | |
| 1264 paint.isAntiAlias(), | |
| 1265 ovalRect, | |
| 1266 strokeInfo)) { | |
| 1267 return; | |
| 1268 } | |
| 1269 } | |
| 1270 } | |
| 1271 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.is
AntiAlias(), | |
| 1272 path, strokeInfo); | |
| 1273 } | |
| 1274 | |
| 1275 void GrContext::internalDrawPath(GrDrawTarget* target, | |
| 1276 GrPipelineBuilder* pipelineBuilder, | |
| 1277 const SkMatrix& viewMatrix, | |
| 1278 GrColor color, | |
| 1279 bool useAA, | |
| 1280 const SkPath& path, | |
| 1281 const GrStrokeInfo& strokeInfo) { | |
| 1282 RETURN_IF_ABANDONED | |
| 1283 SkASSERT(!path.isEmpty()); | |
| 1284 | |
| 1285 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target); | |
| 1286 | |
| 1287 | |
| 1288 // An Assumption here is that path renderer would use some form of tweaking | |
| 1289 // the src color (either the input alpha or in the frag shader) to implement | |
| 1290 // aa. If we have some future driver-mojo path AA that can do the right | |
| 1291 // thing WRT to the blend then we'll need some query on the PR. | |
| 1292 bool useCoverageAA = useAA && | |
| 1293 !pipelineBuilder->getRenderTarget()->isMultisampled(); | |
| 1294 | |
| 1295 | |
| 1296 GrPathRendererChain::DrawType type = | |
| 1297 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType : | |
| 1298 GrPathRendererChain::kColor_DrawType; | |
| 1299 | |
| 1300 const SkPath* pathPtr = &path; | |
| 1301 SkTLazy<SkPath> tmpPath; | |
| 1302 const GrStrokeInfo* strokeInfoPtr = &strokeInfo; | |
| 1303 | |
| 1304 // Try a 1st time without stroking the path and without allowing the SW rend
erer | |
| 1305 GrPathRenderer* pr = this->getPathRenderer(target, pipelineBuilder, viewMatr
ix, *pathPtr, | |
| 1306 *strokeInfoPtr, false, type); | |
| 1307 | |
| 1308 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false); | |
| 1309 if (NULL == pr && strokeInfo.isDashed()) { | |
| 1310 // It didn't work above, so try again with dashed stroke converted to a
dashless stroke. | |
| 1311 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pa
thPtr)) { | |
| 1312 return; | |
| 1313 } | |
| 1314 pathPtr = tmpPath.get(); | |
| 1315 if (pathPtr->isEmpty()) { | |
| 1316 return; | |
| 1317 } | |
| 1318 strokeInfoPtr = &dashlessStrokeInfo; | |
| 1319 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr
, *strokeInfoPtr, | |
| 1320 false, type); | |
| 1321 } | |
| 1322 | |
| 1323 if (NULL == pr) { | |
| 1324 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMa
trix, NULL) && | |
| 1325 !strokeInfoPtr->isFillStyle()) { | |
| 1326 // It didn't work above, so try again with stroke converted to a fil
l. | |
| 1327 if (!tmpPath.isValid()) { | |
| 1328 tmpPath.init(); | |
| 1329 } | |
| 1330 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale())
); | |
| 1331 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) { | |
| 1332 return; | |
| 1333 } | |
| 1334 pathPtr = tmpPath.get(); | |
| 1335 if (pathPtr->isEmpty()) { | |
| 1336 return; | |
| 1337 } | |
| 1338 dashlessStrokeInfo.setFillStyle(); | |
| 1339 strokeInfoPtr = &dashlessStrokeInfo; | |
| 1340 } | |
| 1341 | |
| 1342 // This time, allow SW renderer | |
| 1343 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr
, *strokeInfoPtr, | |
| 1344 true, type); | |
| 1345 } | |
| 1346 | |
| 1347 if (NULL == pr) { | |
| 1348 #ifdef SK_DEBUG | |
| 1349 SkDebugf("Unable to find path renderer compatible with path.\n"); | |
| 1350 #endif | |
| 1351 return; | |
| 1352 } | |
| 1353 | |
| 1354 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeIn
foPtr, useCoverageAA); | |
| 1355 } | |
| 1356 | |
| 1357 //////////////////////////////////////////////////////////////////////////////// | 307 //////////////////////////////////////////////////////////////////////////////// |
| 1358 | 308 |
| 1359 void GrContext::flush(int flagsBitfield) { | 309 void GrContext::flush(int flagsBitfield) { |
| 1360 if (NULL == fDrawBuffer) { | 310 RETURN_IF_ABANDONED |
| 1361 return; | |
| 1362 } | |
| 1363 | 311 |
| 1364 if (kDiscard_FlushBit & flagsBitfield) { | 312 if (kDiscard_FlushBit & flagsBitfield) { |
| 1365 fDrawBuffer->reset(); | 313 fDrawingMgr.reset(); |
| 1366 } else { | 314 } else { |
| 1367 fDrawBuffer->flush(); | 315 fDrawingMgr.flush(); |
| 1368 } | 316 } |
| 1369 fResourceCache->notifyFlushOccurred(); | 317 fResourceCache->notifyFlushOccurred(); |
| 1370 fFlushToReduceCacheSize = false; | 318 fFlushToReduceCacheSize = false; |
| 1371 } | 319 } |
| 1372 | 320 |
| 1373 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t
inRowBytes, | 321 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t
inRowBytes, |
| 1374 const void* inPixels, size_t outRowBytes, void* outPix
els) { | 322 const void* inPixels, size_t outRowBytes, void* outPix
els) { |
| 1375 SkSrcPixelInfo srcPI; | 323 SkSrcPixelInfo srcPI; |
| 1376 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL))
{ | 324 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL))
{ |
| 1377 return false; | 325 return false; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1405 } | 353 } |
| 1406 return fGpu->writeTexturePixels(texture, left, top, width, height, | 354 return fGpu->writeTexturePixels(texture, left, top, width, height, |
| 1407 srcConfig, buffer, rowBytes); | 355 srcConfig, buffer, rowBytes); |
| 1408 // Don't need to check kFlushWrites_PixelOp here, we just did a dire
ct write so the | 356 // Don't need to check kFlushWrites_PixelOp here, we just did a dire
ct write so the |
| 1409 // upload is already flushed. | 357 // upload is already flushed. |
| 1410 } | 358 } |
| 1411 } | 359 } |
| 1412 | 360 |
| 1413 // If we didn't do a direct texture write then we upload the pixels to a tex
ture and draw. | 361 // If we didn't do a direct texture write then we upload the pixels to a tex
ture and draw. |
| 1414 GrRenderTarget* renderTarget = surface->asRenderTarget(); | 362 GrRenderTarget* renderTarget = surface->asRenderTarget(); |
| 1415 if (NULL == renderTarget) { | 363 if (!renderTarget) { |
| 1416 return false; | 364 return false; |
| 1417 } | 365 } |
| 1418 | 366 |
| 1419 // We ignore the preferred config unless it is a R/B swap of the src config.
In that case | 367 // We ignore the preferred config unless it is a R/B swap of the src config.
In that case |
| 1420 // we will upload the original src data to a scratch texture but we will spo
of it as the swapped | 368 // we will upload the original src data to a scratch texture but we will spo
of it as the swapped |
| 1421 // config. This scratch will then have R and B swapped. We correct for this
by swapping again | 369 // config. This scratch will then have R and B swapped. We correct for this
by swapping again |
| 1422 // when drawing the scratch to the dst using a conversion effect. | 370 // when drawing the scratch to the dst using a conversion effect. |
| 1423 bool swapRAndB = false; | 371 bool swapRAndB = false; |
| 1424 GrPixelConfig writeConfig = srcConfig; | 372 GrPixelConfig writeConfig = srcConfig; |
| 1425 if (GrPixelConfigSwapRAndB(srcConfig) == | 373 if (GrPixelConfigSwapRAndB(srcConfig) == |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1444 | 392 |
| 1445 // allocate a tmp buffer and sw convert the pixels to premul | 393 // allocate a tmp buffer and sw convert the pixels to premul |
| 1446 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); | 394 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); |
| 1447 | 395 |
| 1448 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { | 396 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { |
| 1449 if (!GrPixelConfigIs8888(srcConfig)) { | 397 if (!GrPixelConfigIs8888(srcConfig)) { |
| 1450 return false; | 398 return false; |
| 1451 } | 399 } |
| 1452 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); | 400 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); |
| 1453 // handle the unpremul step on the CPU if we couldn't create an effect t
o do it. | 401 // handle the unpremul step on the CPU if we couldn't create an effect t
o do it. |
| 1454 if (NULL == fp) { | 402 if (!fp) { |
| 1455 size_t tmpRowBytes = 4 * width; | 403 size_t tmpRowBytes = 4 * width; |
| 1456 tmpPixels.reset(width * height); | 404 tmpPixels.reset(width * height); |
| 1457 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer
, tmpRowBytes, | 405 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer
, tmpRowBytes, |
| 1458 tmpPixels.get())) { | 406 tmpPixels.get())) { |
| 1459 return false; | 407 return false; |
| 1460 } | 408 } |
| 1461 rowBytes = tmpRowBytes; | 409 rowBytes = tmpRowBytes; |
| 1462 buffer = tmpPixels.get(); | 410 buffer = tmpPixels.get(); |
| 1463 } | 411 } |
| 1464 } | 412 } |
| 1465 if (NULL == fp) { | 413 if (!fp) { |
| 1466 fp.reset(GrConfigConversionEffect::Create(texture, | 414 fp.reset(GrConfigConversionEffect::Create(texture, |
| 1467 swapRAndB, | 415 swapRAndB, |
| 1468 GrConfigConversionEffect::kNon
e_PMConversion, | 416 GrConfigConversionEffect::kNon
e_PMConversion, |
| 1469 textureMatrix)); | 417 textureMatrix)); |
| 1470 } | 418 } |
| 1471 | 419 |
| 1472 // Even if the client told us not to flush, we still flush here. The client
may have known that | 420 // Even if the client told us not to flush, we still flush here. The client
may have known that |
| 1473 // writes to the original surface caused no data hazards, but they can't kno
w that the scratch | 421 // writes to the original surface caused no data hazards, but they can't kno
w that the scratch |
| 1474 // we just got is safe. | 422 // we just got is safe. |
| 1475 if (texture->surfacePriv().hasPendingIO()) { | 423 if (texture->surfacePriv().hasPendingIO()) { |
| 1476 this->flush(); | 424 this->flush(); |
| 1477 } | 425 } |
| 1478 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height, | 426 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height, |
| 1479 writeConfig, buffer, rowBytes)) { | 427 writeConfig, buffer, rowBytes)) { |
| 1480 return false; | 428 return false; |
| 1481 } | 429 } |
| 1482 | 430 |
| 1483 SkMatrix matrix; | 431 SkMatrix matrix; |
| 1484 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); | 432 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); |
| 1485 | 433 |
| 1486 // This function can be called in the midst of drawing another object (e.g.,
when uploading a | 434 GrDrawContext* drawContext = this->drawContext(); |
| 1487 // SW-rasterized clip while issuing a draw). So we push the current geometry
state before | 435 if (!drawContext) { |
| 1488 // drawing a rect to the render target. | 436 return false; |
| 1489 // The bracket ensures we pop the stack if we wind up flushing below. | 437 } |
| 1490 { | |
| 1491 GrDrawTarget* drawTarget = this->prepareToDraw(); | |
| 1492 if (!drawTarget) { | |
| 1493 return false; | |
| 1494 } | |
| 1495 | 438 |
| 1496 GrPipelineBuilder pipelineBuilder; | 439 GrPaint paint; |
| 1497 pipelineBuilder.addColorProcessor(fp); | 440 paint.addColorProcessor(fp); |
| 1498 pipelineBuilder.setRenderTarget(renderTarget); | 441 |
| 1499 drawTarget->drawSimpleRect(&pipelineBuilder, | 442 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); |
| 1500 GrColor_WHITE, | 443 |
| 1501 matrix, | 444 drawContext->drawRect(renderTarget, GrClip::WideOpen(), paint, matrix, rect,
NULL); |
| 1502 SkRect::MakeWH(SkIntToScalar(width), SkIntToS
calar(height))); | |
| 1503 } | |
| 1504 | 445 |
| 1505 if (kFlushWrites_PixelOp & pixelOpsFlags) { | 446 if (kFlushWrites_PixelOp & pixelOpsFlags) { |
| 1506 this->flushSurfaceWrites(surface); | 447 this->flushSurfaceWrites(surface); |
| 1507 } | 448 } |
| 1508 | 449 |
| 1509 return true; | 450 return true; |
| 1510 } | 451 } |
| 1511 | 452 |
| 1512 // toggles between RGBA and BGRA | 453 // toggles between RGBA and BGRA |
| 1513 static SkColorType toggle_colortype32(SkColorType ct) { | 454 static SkColorType toggle_colortype32(SkColorType ct) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1607 fp.reset(GrConfigConversionEffect::Create( | 548 fp.reset(GrConfigConversionEffect::Create( |
| 1608 src, swapRAndB, GrConfigConversionEffect::kNone_PMCo
nversion, | 549 src, swapRAndB, GrConfigConversionEffect::kNone_PMCo
nversion, |
| 1609 textureMatrix)); | 550 textureMatrix)); |
| 1610 } | 551 } |
| 1611 swapRAndB = false; // we will handle the swap in the draw. | 552 swapRAndB = false; // we will handle the swap in the draw. |
| 1612 | 553 |
| 1613 // We protect the existing geometry here since it may not be | 554 // We protect the existing geometry here since it may not be |
| 1614 // clear to the caller that a draw operation (i.e., drawSimpleRe
ct) | 555 // clear to the caller that a draw operation (i.e., drawSimpleRe
ct) |
| 1615 // can be invoked in this method | 556 // can be invoked in this method |
| 1616 { | 557 { |
| 1617 GrPipelineBuilder pipelineBuilder; | 558 GrDrawContext* drawContext = this->drawContext(); |
| 1618 SkASSERT(fp); | 559 if (!drawContext) { |
| 1619 pipelineBuilder.addColorProcessor(fp); | 560 return false; |
| 561 } |
| 1620 | 562 |
| 1621 pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget(
)); | 563 GrPaint paint; |
| 564 paint.addColorProcessor(fp); |
| 565 |
| 1622 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToSc
alar(height)); | 566 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToSc
alar(height)); |
| 1623 fDrawBuffer->drawSimpleRect(&pipelineBuilder, | 567 |
| 1624 GrColor_WHITE, | 568 drawContext->drawRect(tempTexture->asRenderTarget(), GrClip:
:WideOpen(), paint, |
| 1625 SkMatrix::I(), | 569 SkMatrix::I(), rect, NULL);
|
| 1626 rect); | 570 |
| 1627 // we want to read back from the scratch's origin | 571 // we want to read back from the scratch's origin |
| 1628 left = 0; | 572 left = 0; |
| 1629 top = 0; | 573 top = 0; |
| 1630 target = tempTexture->asRenderTarget(); | 574 target = tempTexture->asRenderTarget(); |
| 1631 } | 575 } |
| 1632 this->flushSurfaceWrites(target); | 576 this->flushSurfaceWrites(target); |
| 1633 } | 577 } |
| 1634 } | 578 } |
| 1635 } | 579 } |
| 1636 | 580 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1666 ASSERT_OWNED_RESOURCE(surface); | 610 ASSERT_OWNED_RESOURCE(surface); |
| 1667 if (surface->surfacePriv().hasPendingIO()) { | 611 if (surface->surfacePriv().hasPendingIO()) { |
| 1668 this->flush(); | 612 this->flush(); |
| 1669 } | 613 } |
| 1670 GrRenderTarget* rt = surface->asRenderTarget(); | 614 GrRenderTarget* rt = surface->asRenderTarget(); |
| 1671 if (fGpu && rt) { | 615 if (fGpu && rt) { |
| 1672 fGpu->resolveRenderTarget(rt); | 616 fGpu->resolveRenderTarget(rt); |
| 1673 } | 617 } |
| 1674 } | 618 } |
| 1675 | 619 |
| 1676 void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) { | |
| 1677 RETURN_IF_ABANDONED | |
| 1678 SkASSERT(renderTarget); | |
| 1679 ASSERT_OWNED_RESOURCE(renderTarget); | |
| 1680 AutoCheckFlush acf(this); | |
| 1681 GrDrawTarget* target = this->prepareToDraw(); | |
| 1682 if (NULL == target) { | |
| 1683 return; | |
| 1684 } | |
| 1685 target->discard(renderTarget); | |
| 1686 } | |
| 1687 | |
| 1688 void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe
ct, | 620 void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRe
ct, |
| 1689 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) { | 621 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) { |
| 1690 RETURN_IF_ABANDONED | 622 RETURN_IF_ABANDONED |
| 1691 if (NULL == src || NULL == dst) { | 623 if (!src || !dst) { |
| 1692 return; | 624 return; |
| 1693 } | 625 } |
| 1694 ASSERT_OWNED_RESOURCE(src); | 626 ASSERT_OWNED_RESOURCE(src); |
| 1695 ASSERT_OWNED_RESOURCE(dst); | 627 ASSERT_OWNED_RESOURCE(dst); |
| 1696 | 628 |
| 1697 // Since we're going to the draw target and not GPU, no need to check kNoFlu
sh | 629 // Since we're going to the draw target and not GPU, no need to check kNoFlu
sh |
| 1698 // here. | 630 // here. |
| 1699 | 631 if (!dst->asRenderTarget()) { |
| 1700 GrDrawTarget* target = this->prepareToDraw(); | |
| 1701 if (NULL == target) { | |
| 1702 return; | 632 return; |
| 1703 } | 633 } |
| 1704 target->copySurface(dst, src, srcRect, dstPoint); | 634 |
| 635 GrDrawContext* drawContext = this->drawContext(); |
| 636 if (!drawContext) { |
| 637 return; |
| 638 } |
| 639 |
| 640 drawContext->copySurface(dst->asRenderTarget(), src, srcRect, dstPoint); |
| 1705 | 641 |
| 1706 if (kFlushWrites_PixelOp & pixelOpsFlags) { | 642 if (kFlushWrites_PixelOp & pixelOpsFlags) { |
| 1707 this->flush(); | 643 this->flush(); |
| 1708 } | 644 } |
| 1709 } | 645 } |
| 1710 | 646 |
| 1711 void GrContext::flushSurfaceWrites(GrSurface* surface) { | 647 void GrContext::flushSurfaceWrites(GrSurface* surface) { |
| 1712 RETURN_IF_ABANDONED | 648 RETURN_IF_ABANDONED |
| 1713 if (surface->surfacePriv().hasPendingWrite()) { | 649 if (surface->surfacePriv().hasPendingWrite()) { |
| 1714 this->flush(); | 650 this->flush(); |
| 1715 } | 651 } |
| 1716 } | 652 } |
| 1717 | 653 |
| 1718 GrDrawTarget* GrContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder, | |
| 1719 GrRenderTarget* rt, | |
| 1720 const GrClip& clip, | |
| 1721 const GrPaint* paint, | |
| 1722 const AutoCheckFlush* acf) { | |
| 1723 if (NULL == fGpu || NULL == fDrawBuffer) { | |
| 1724 return NULL; | |
| 1725 } | |
| 1726 | |
| 1727 ASSERT_OWNED_RESOURCE(rt); | |
| 1728 SkASSERT(rt && paint && acf); | |
| 1729 pipelineBuilder->setFromPaint(*paint, rt, clip); | |
| 1730 return fDrawBuffer; | |
| 1731 } | |
| 1732 | |
| 1733 GrDrawTarget* GrContext::prepareToDraw() { | |
| 1734 if (NULL == fGpu) { | |
| 1735 return NULL; | |
| 1736 } | |
| 1737 return fDrawBuffer; | |
| 1738 } | |
| 1739 | |
| 1740 /* | 654 /* |
| 1741 * This method finds a path renderer that can draw the specified path on | 655 * This method finds a path renderer that can draw the specified path on |
| 1742 * the provided target. | 656 * the provided target. |
| 1743 * Due to its expense, the software path renderer has split out so it can | 657 * Due to its expense, the software path renderer has split out so it can |
| 1744 * can be individually allowed/disallowed via the "allowSW" boolean. | 658 * can be individually allowed/disallowed via the "allowSW" boolean. |
| 1745 */ | 659 */ |
| 1746 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, | 660 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, |
| 1747 const GrPipelineBuilder* pipelineBuil
der, | 661 const GrPipelineBuilder* pipelineBuil
der, |
| 1748 const SkMatrix& viewMatrix, | 662 const SkMatrix& viewMatrix, |
| 1749 const SkPath& path, | 663 const SkPath& path, |
| 1750 const GrStrokeInfo& stroke, | 664 const GrStrokeInfo& stroke, |
| 1751 bool allowSW, | 665 bool allowSW, |
| 1752 GrPathRendererChain::DrawType drawTyp
e, | 666 GrPathRendererChain::DrawType drawTyp
e, |
| 1753 GrPathRendererChain::StencilSupport*
stencilSupport) { | 667 GrPathRendererChain::StencilSupport*
stencilSupport) { |
| 1754 | 668 |
| 1755 if (NULL == fPathRendererChain) { | 669 if (!fPathRendererChain) { |
| 1756 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this)); | 670 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this)); |
| 1757 } | 671 } |
| 1758 | 672 |
| 1759 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target, | 673 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target, |
| 1760 pipelineBuilder, | 674 pipelineBuilder, |
| 1761 viewMatrix, | 675 viewMatrix, |
| 1762 path, | 676 path, |
| 1763 stroke, | 677 stroke, |
| 1764 drawType, | 678 drawType, |
| 1765 stencilSupport); | 679 stencilSupport); |
| 1766 | 680 |
| 1767 if (NULL == pr && allowSW) { | 681 if (!pr && allowSW) { |
| 1768 if (NULL == fSoftwarePathRenderer) { | 682 if (!fSoftwarePathRenderer) { |
| 1769 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this)); | 683 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this)); |
| 1770 } | 684 } |
| 1771 pr = fSoftwarePathRenderer; | 685 pr = fSoftwarePathRenderer; |
| 1772 } | 686 } |
| 1773 | 687 |
| 1774 return pr; | 688 return pr; |
| 1775 } | 689 } |
| 1776 | 690 |
| 1777 //////////////////////////////////////////////////////////////////////////////// | 691 //////////////////////////////////////////////////////////////////////////////// |
| 1778 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const { | 692 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1789 if (dpi >= 250.0f) { | 703 if (dpi >= 250.0f) { |
| 1790 chosenSampleCount = 4; | 704 chosenSampleCount = 4; |
| 1791 } else { | 705 } else { |
| 1792 chosenSampleCount = 16; | 706 chosenSampleCount = 16; |
| 1793 } | 707 } |
| 1794 } | 708 } |
| 1795 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? | 709 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? |
| 1796 chosenSampleCount : 0; | 710 chosenSampleCount : 0; |
| 1797 } | 711 } |
| 1798 | 712 |
| 1799 GrDrawTarget* GrContext::getTextTarget() { | |
| 1800 return this->prepareToDraw(); | |
| 1801 } | |
| 1802 | |
| 1803 namespace { | 713 namespace { |
| 1804 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { | 714 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { |
| 1805 GrConfigConversionEffect::PMConversion pmToUPM; | 715 GrConfigConversionEffect::PMConversion pmToUPM; |
| 1806 GrConfigConversionEffect::PMConversion upmToPM; | 716 GrConfigConversionEffect::PMConversion upmToPM; |
| 1807 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upm
ToPM); | 717 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upm
ToPM); |
| 1808 *pmToUPMValue = pmToUPM; | 718 *pmToUPMValue = pmToUPM; |
| 1809 *upmToPMValue = upmToPM; | 719 *upmToPMValue = upmToPM; |
| 1810 } | 720 } |
| 1811 } | 721 } |
| 1812 | 722 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1854 } | 764 } |
| 1855 | 765 |
| 1856 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes)
{ | 766 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes)
{ |
| 1857 fResourceCache->setLimits(maxTextures, maxTextureBytes); | 767 fResourceCache->setLimits(maxTextures, maxTextureBytes); |
| 1858 } | 768 } |
| 1859 | 769 |
| 1860 ////////////////////////////////////////////////////////////////////////////// | 770 ////////////////////////////////////////////////////////////////////////////// |
| 1861 | 771 |
| 1862 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { | 772 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { |
| 1863 fGpu->addGpuTraceMarker(marker); | 773 fGpu->addGpuTraceMarker(marker); |
| 1864 if (fDrawBuffer) { | |
| 1865 fDrawBuffer->addGpuTraceMarker(marker); | |
| 1866 } | |
| 1867 } | 774 } |
| 1868 | 775 |
| 1869 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { | 776 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { |
| 1870 fGpu->removeGpuTraceMarker(marker); | 777 fGpu->removeGpuTraceMarker(marker); |
| 1871 if (fDrawBuffer) { | |
| 1872 fDrawBuffer->removeGpuTraceMarker(marker); | |
| 1873 } | |
| 1874 } | 778 } |
| 1875 | 779 |
| 1876 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | |
| 1877 | |
| 1878 #ifdef GR_TEST_UTILS | |
| 1879 | |
| 1880 BATCH_TEST_DEFINE(StrokeRectBatch) { | |
| 1881 StrokeRectBatch::Geometry geometry; | |
| 1882 geometry.fViewMatrix = GrTest::TestMatrix(random); | |
| 1883 geometry.fColor = GrRandomColor(random); | |
| 1884 geometry.fRect = GrTest::TestRect(random); | |
| 1885 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f; | |
| 1886 | |
| 1887 return StrokeRectBatch::Create(geometry, random->nextBool()); | |
| 1888 } | |
| 1889 | |
| 1890 static uint32_t seed_vertices(GrPrimitiveType type) { | |
| 1891 switch (type) { | |
| 1892 case kTriangles_GrPrimitiveType: | |
| 1893 case kTriangleStrip_GrPrimitiveType: | |
| 1894 case kTriangleFan_GrPrimitiveType: | |
| 1895 return 3; | |
| 1896 case kPoints_GrPrimitiveType: | |
| 1897 return 1; | |
| 1898 case kLines_GrPrimitiveType: | |
| 1899 case kLineStrip_GrPrimitiveType: | |
| 1900 return 2; | |
| 1901 } | |
| 1902 SkFAIL("Incomplete switch\n"); | |
| 1903 return 0; | |
| 1904 } | |
| 1905 | |
| 1906 static uint32_t primitive_vertices(GrPrimitiveType type) { | |
| 1907 switch (type) { | |
| 1908 case kTriangles_GrPrimitiveType: | |
| 1909 return 3; | |
| 1910 case kLines_GrPrimitiveType: | |
| 1911 return 2; | |
| 1912 case kTriangleStrip_GrPrimitiveType: | |
| 1913 case kTriangleFan_GrPrimitiveType: | |
| 1914 case kPoints_GrPrimitiveType: | |
| 1915 case kLineStrip_GrPrimitiveType: | |
| 1916 return 1; | |
| 1917 } | |
| 1918 SkFAIL("Incomplete switch\n"); | |
| 1919 return 0; | |
| 1920 } | |
| 1921 | |
| 1922 static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) { | |
| 1923 SkPoint p; | |
| 1924 p.fX = random->nextRangeScalar(min, max); | |
| 1925 p.fY = random->nextRangeScalar(min, max); | |
| 1926 return p; | |
| 1927 } | |
| 1928 | |
| 1929 static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkSca
lar max, | |
| 1930 SkRandom* random, | |
| 1931 SkTArray<SkPoint>* positions, | |
| 1932 SkTArray<SkPoint>* texCoords, bool hasTexCoords, | |
| 1933 SkTArray<GrColor>* colors, bool hasColors, | |
| 1934 SkTArray<uint16_t>* indices, bool hasIndices) { | |
| 1935 for (uint32_t v = 0; v < count; v++) { | |
| 1936 positions->push_back(random_point(random, min, max)); | |
| 1937 if (hasTexCoords) { | |
| 1938 texCoords->push_back(random_point(random, min, max)); | |
| 1939 } | |
| 1940 if (hasColors) { | |
| 1941 colors->push_back(GrRandomColor(random)); | |
| 1942 } | |
| 1943 if (hasIndices) { | |
| 1944 SkASSERT(maxVertex <= SK_MaxU16); | |
| 1945 indices->push_back(random->nextULessThan((uint16_t)maxVertex)); | |
| 1946 } | |
| 1947 } | |
| 1948 } | |
| 1949 | |
| 1950 BATCH_TEST_DEFINE(VerticesBatch) { | |
| 1951 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimiti
veType + 1)); | |
| 1952 uint32_t primitiveCount = random->nextRangeU(1, 100); | |
| 1953 | |
| 1954 // TODO make 'sensible' indexbuffers | |
| 1955 SkTArray<SkPoint> positions; | |
| 1956 SkTArray<SkPoint> texCoords; | |
| 1957 SkTArray<GrColor> colors; | |
| 1958 SkTArray<uint16_t> indices; | |
| 1959 | |
| 1960 bool hasTexCoords = random->nextBool(); | |
| 1961 bool hasIndices = random->nextBool(); | |
| 1962 bool hasColors = random->nextBool(); | |
| 1963 | |
| 1964 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitiv
e_vertices(type); | |
| 1965 | |
| 1966 static const SkScalar kMinVertExtent = -100.f; | |
| 1967 static const SkScalar kMaxVertExtent = 100.f; | |
| 1968 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertE
xtent, | |
| 1969 random, | |
| 1970 &positions, | |
| 1971 &texCoords, hasTexCoords, | |
| 1972 &colors, hasColors, | |
| 1973 &indices, hasIndices); | |
| 1974 | |
| 1975 for (uint32_t i = 1; i < primitiveCount; i++) { | |
| 1976 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent,
kMaxVertExtent, | |
| 1977 random, | |
| 1978 &positions, | |
| 1979 &texCoords, hasTexCoords, | |
| 1980 &colors, hasColors, | |
| 1981 &indices, hasIndices); | |
| 1982 } | |
| 1983 | |
| 1984 SkMatrix viewMatrix = GrTest::TestMatrix(random); | |
| 1985 SkRect bounds; | |
| 1986 SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexC
ount); | |
| 1987 SkASSERT(result); | |
| 1988 | |
| 1989 viewMatrix.mapRect(&bounds); | |
| 1990 | |
| 1991 DrawVerticesBatch::Geometry geometry; | |
| 1992 geometry.fColor = GrRandomColor(random); | |
| 1993 return DrawVerticesBatch::Create(geometry, type, viewMatrix, | |
| 1994 positions.begin(), vertexCount, | |
| 1995 indices.begin(), hasIndices ? vertexCount :
0, | |
| 1996 colors.begin(), | |
| 1997 texCoords.begin(), | |
| 1998 bounds); | |
| 1999 } | |
| 2000 | |
| 2001 #endif | |
| OLD | NEW |