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