Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2011 Google Inc. | 3 * Copyright 2015 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" | |
| 10 | |
| 11 #include "GrAARectRenderer.h" | 9 #include "GrAARectRenderer.h" |
| 12 #include "GrAtlasTextContext.h" | |
| 13 #include "GrBatch.h" | |
| 14 #include "GrBatchFontCache.h" | |
| 15 #include "GrBatchTarget.h" | |
| 16 #include "GrBatchTest.h" | 10 #include "GrBatchTest.h" |
| 17 #include "GrDefaultGeoProcFactory.h" | 11 #include "GrDefaultGeoProcFactory.h" |
| 18 #include "GrGpuResource.h" | 12 #include "GrDrawContext.h" |
| 19 #include "GrGpuResourcePriv.h" | |
| 20 #include "GrDrawTargetCaps.h" | |
| 21 #include "GrGpu.h" | |
| 22 #include "GrImmediateDrawTarget.h" | |
| 23 #include "GrIndexBuffer.h" | |
| 24 #include "GrInOrderDrawBuffer.h" | |
| 25 #include "GrLayerCache.h" | |
| 26 #include "GrOvalRenderer.h" | 13 #include "GrOvalRenderer.h" |
| 27 #include "GrPathRenderer.h" | 14 #include "GrPathRenderer.h" |
| 28 #include "GrPathUtils.h" | |
| 29 #include "GrRenderTargetPriv.h" | |
| 30 #include "GrResourceCache.h" | |
| 31 #include "GrResourceProvider.h" | |
| 32 #include "GrSoftwarePathRenderer.h" | |
| 33 #include "GrStencilAndCoverTextContext.h" | |
| 34 #include "GrStrokeInfo.h" | |
| 35 #include "GrSurfacePriv.h" | |
| 36 #include "GrTextBlobCache.h" | |
| 37 #include "GrTexturePriv.h" | |
| 38 #include "GrTraceMarker.h" | |
| 39 #include "GrTracing.h" | 15 #include "GrTracing.h" |
| 40 #include "GrVertices.h" | |
| 41 #include "SkDashPathPriv.h" | |
| 42 #include "SkConfig8888.h" | |
| 43 #include "SkGr.h" | |
| 44 #include "SkRRect.h" | |
| 45 #include "SkStrokeRec.h" | |
| 46 #include "SkTLazy.h" | |
| 47 #include "SkTLS.h" | |
| 48 #include "SkTraceEvent.h" | |
| 49 | 16 |
| 50 #include "effects/GrConfigConversionEffect.h" | 17 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext) |
| 51 #include "effects/GrDashingEffect.h" | 18 #define RETURN_IF_ABANDONED if (!fDrawTarget) { return; } |
| 52 #include "effects/GrSingleTextureEffect.h" | 19 #define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; } |
| 20 #define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; } | |
| 53 | 21 |
| 54 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) | 22 class AutoCheckFlush { |
| 55 #define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; } | |
| 56 #define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; } | |
| 57 #define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; } | |
| 58 | |
| 59 class GrContext::AutoCheckFlush { | |
| 60 public: | 23 public: |
| 61 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); } | 24 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); } |
| 62 | 25 ~AutoCheckFlush() { fContext->flushIfNecessary(); } |
|
bsalomon
2015/05/22 20:33:58
Is it possible for the flushing to be moved to the
robertphillips
2015/05/26 16:12:58
I think this check could go away when we're in a w
| |
| 63 ~AutoCheckFlush() { | |
| 64 if (fContext->fFlushToReduceCacheSize) { | |
| 65 fContext->flush(); | |
| 66 } | |
| 67 } | |
| 68 | 26 |
| 69 private: | 27 private: |
| 70 GrContext* fContext; | 28 GrContext* fContext; |
| 71 }; | 29 }; |
| 72 | 30 |
| 73 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, | 31 GrDrawContext::GrDrawContext(GrContext* context, GrDrawTarget* drawTarget) |
| 74 const Options* opts) { | 32 : fContext(context) |
| 75 GrContext* context; | 33 , fDrawTarget(SkRef(drawTarget)) { |
| 76 if (NULL == opts) { | |
| 77 context = SkNEW_ARGS(GrContext, (Options())); | |
| 78 } else { | |
| 79 context = SkNEW_ARGS(GrContext, (*opts)); | |
| 80 } | |
| 81 | |
| 82 if (context->init(backend, backendContext)) { | |
| 83 return context; | |
| 84 } else { | |
| 85 context->unref(); | |
| 86 return NULL; | |
| 87 } | |
| 88 } | 34 } |
| 89 | 35 |
| 90 static int32_t gNextID = 1; | 36 void GrDrawContext::copySurface(GrRenderTarget* dst, GrSurface* src, |
| 91 static int32_t next_id() { | 37 const SkIRect& srcRect, const SkIPoint& dstPoint ) { |
| 92 int32_t id; | 38 if (!this->prepareToDraw(dst)) { |
| 93 do { | |
| 94 id = sk_atomic_inc(&gNextID); | |
| 95 } while (id == SK_InvalidGenID); | |
| 96 return id; | |
| 97 } | |
| 98 | |
| 99 GrContext::GrContext(const Options& opts) : fOptions(opts), fUniqueID(next_id()) { | |
| 100 fGpu = NULL; | |
| 101 fResourceCache = NULL; | |
| 102 fResourceProvider = NULL; | |
| 103 fPathRendererChain = NULL; | |
| 104 fSoftwarePathRenderer = NULL; | |
| 105 fBatchFontCache = NULL; | |
| 106 fDrawBuffer = NULL; | |
| 107 fFlushToReduceCacheSize = false; | |
| 108 fAARectRenderer = NULL; | |
| 109 fOvalRenderer = NULL; | |
| 110 fMaxTextureSizeOverride = 1 << 20; | |
| 111 } | |
| 112 | |
| 113 bool GrContext::init(GrBackend backend, GrBackendContext backendContext) { | |
| 114 SkASSERT(NULL == fGpu); | |
| 115 | |
| 116 fGpu = GrGpu::Create(backend, backendContext, this); | |
| 117 if (NULL == fGpu) { | |
| 118 return false; | |
| 119 } | |
| 120 this->initCommon(); | |
| 121 return true; | |
| 122 } | |
| 123 | |
| 124 void GrContext::initCommon() { | |
| 125 fResourceCache = SkNEW(GrResourceCache); | |
| 126 fResourceCache->setOverBudgetCallback(OverBudgetCB, this); | |
| 127 fResourceProvider = SkNEW_ARGS(GrResourceProvider, (fGpu, fResourceCache)); | |
| 128 | |
| 129 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this))); | |
| 130 | |
| 131 fAARectRenderer = SkNEW(GrAARectRenderer); | |
| 132 fOvalRenderer = SkNEW(GrOvalRenderer); | |
| 133 | |
| 134 fDidTestPMConversions = false; | |
| 135 | |
| 136 #ifdef IMMEDIATE_MODE | |
| 137 fDrawBuffer = SkNEW_ARGS(GrImmediateDrawTarget, (this)); | |
| 138 #else | |
| 139 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (this)); | |
| 140 #endif | |
| 141 | |
| 142 // GrBatchFontCache will eventually replace GrFontCache | |
| 143 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this)); | |
| 144 | |
| 145 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB, this))); | |
| 146 } | |
| 147 | |
| 148 GrContext::~GrContext() { | |
| 149 if (NULL == fGpu) { | |
| 150 return; | 39 return; |
| 151 } | 40 } |
| 152 | 41 |
| 153 this->flush(); | 42 fDrawTarget->copySurface(dst, src, srcRect, dstPoint); |
| 154 | |
| 155 for (int i = 0; i < fCleanUpData.count(); ++i) { | |
| 156 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); | |
| 157 } | |
| 158 | |
| 159 SkDELETE(fResourceProvider); | |
| 160 SkDELETE(fResourceCache); | |
| 161 SkDELETE(fBatchFontCache); | |
| 162 SkDELETE(fDrawBuffer); | |
| 163 | |
| 164 fAARectRenderer->unref(); | |
| 165 fOvalRenderer->unref(); | |
| 166 | |
| 167 fGpu->unref(); | |
| 168 SkSafeUnref(fPathRendererChain); | |
| 169 SkSafeUnref(fSoftwarePathRenderer); | |
| 170 } | 43 } |
| 171 | 44 |
| 172 void GrContext::abandonContext() { | 45 void GrDrawContext::drawText(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) { |
| 173 fResourceProvider->abandon(); | 46 fDrawTarget->drawBatch(pipelineBuilder, batch); |
| 174 // abandon first to so destructors | |
| 175 // don't try to free the resources in the API. | |
| 176 fResourceCache->abandonAll(); | |
| 177 | |
| 178 fGpu->contextAbandoned(); | |
| 179 | |
| 180 // a path renderer may be holding onto resources that | |
| 181 // are now unusable | |
| 182 SkSafeSetNull(fPathRendererChain); | |
| 183 SkSafeSetNull(fSoftwarePathRenderer); | |
| 184 | |
| 185 SkDELETE(fDrawBuffer); | |
| 186 fDrawBuffer = NULL; | |
| 187 | |
| 188 fBatchFontCache->freeAll(); | |
| 189 fLayerCache->freeAll(); | |
| 190 fTextBlobCache->freeAll(); | |
| 191 } | 47 } |
| 192 | 48 |
| 193 void GrContext::resetContext(uint32_t state) { | 49 void GrDrawContext::drawPaths(GrPipelineBuilder* pipelineBuilder, |
| 194 fGpu->markContextDirty(state); | 50 const GrPathProcessor* pathProc, |
| 51 const GrPathRange* pathRange, | |
| 52 const void* indices, | |
| 53 GrDrawTarget::PathIndexType indexType, | |
| 54 const float transformValues[], | |
| 55 GrDrawTarget::PathTransformType transformType, | |
| 56 int count, | |
| 57 GrPathRendering::FillType fill) { | |
| 58 fDrawTarget->drawPaths(pipelineBuilder, pathProc, pathRange, | |
| 59 indices, indexType, | |
| 60 transformValues, | |
| 61 transformType, | |
| 62 count, fill); | |
| 195 } | 63 } |
| 196 | 64 |
| 197 void GrContext::freeGpuResources() { | 65 void GrDrawContext::discard(GrRenderTarget* renderTarget) { |
| 198 this->flush(); | 66 RETURN_IF_ABANDONED |
| 199 | 67 SkASSERT(renderTarget); |
| 200 if (fDrawBuffer) { | 68 AutoCheckFlush acf(fContext); |
| 201 fDrawBuffer->purgeResources(); | 69 if (!this->prepareToDraw(renderTarget)) { |
| 70 return; | |
| 202 } | 71 } |
| 203 | 72 fDrawTarget->discard(renderTarget); |
| 204 fBatchFontCache->freeAll(); | |
| 205 fLayerCache->freeAll(); | |
| 206 // a path renderer may be holding onto resources | |
| 207 SkSafeSetNull(fPathRendererChain); | |
| 208 SkSafeSetNull(fSoftwarePathRenderer); | |
| 209 | |
| 210 fResourceCache->purgeAllUnlocked(); | |
| 211 } | 73 } |
| 212 | 74 |
| 213 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const { | 75 void GrDrawContext::clear(GrRenderTarget* renderTarget, |
| 214 if (resourceCount) { | 76 const SkIRect* rect, |
| 215 *resourceCount = fResourceCache->getBudgetedResourceCount(); | 77 const GrColor color, |
| 78 bool canIgnoreRect) { | |
| 79 RETURN_IF_ABANDONED | |
| 80 SkASSERT(renderTarget); | |
| 81 | |
| 82 AutoCheckFlush acf(fContext); | |
| 83 GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawContext::clear", fContext); | |
| 84 if (!this->prepareToDraw(renderTarget)) { | |
| 85 return; | |
| 216 } | 86 } |
| 217 if (resourceBytes) { | 87 fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget); |
| 218 *resourceBytes = fResourceCache->getBudgetedResourceBytes(); | |
| 219 } | |
| 220 } | 88 } |
| 221 | 89 |
| 222 GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget, | |
| 223 SkGpuDevice* gpuDevice, | |
| 224 const SkDeviceProperties& | |
| 225 leakyProperties, | |
| 226 bool enableDistanceFieldFonts) { | |
| 227 if (fGpu->caps()->shaderCaps()->pathRenderingSupport() && renderTarget->isMu ltisampled()) { | |
| 228 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencil Attachment(); | |
| 229 if (sb) { | |
| 230 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyPr operties); | |
| 231 } | |
| 232 } | |
| 233 | 90 |
| 234 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDi stanceFieldFonts); | 91 void GrDrawContext::drawPaint(GrRenderTarget* rt, |
| 235 } | 92 const GrClip& clip, |
| 236 | 93 const GrPaint& origPaint, |
| 237 //////////////////////////////////////////////////////////////////////////////// | 94 const SkMatrix& viewMatrix) { |
| 238 | |
| 239 bool GrContext::isConfigTexturable(GrPixelConfig config) const { | |
| 240 return fGpu->caps()->isConfigTexturable(config); | |
| 241 } | |
| 242 | |
| 243 bool GrContext::npotTextureTileSupport() const { | |
| 244 return fGpu->caps()->npotTextureTileSupport(); | |
| 245 } | |
| 246 | |
| 247 void GrContext::OverBudgetCB(void* data) { | |
| 248 SkASSERT(data); | |
| 249 | |
| 250 GrContext* context = reinterpret_cast<GrContext*>(data); | |
| 251 | |
| 252 // Flush the InOrderDrawBuffer to possibly free up some textures | |
| 253 context->fFlushToReduceCacheSize = true; | |
| 254 } | |
| 255 | |
| 256 void GrContext::TextBlobCacheOverBudgetCB(void* data) { | |
| 257 SkASSERT(data); | |
| 258 | |
| 259 // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they | |
| 260 // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The solution is to move | |
| 261 // drawText calls to below the GrContext level, but this is not trivial beca use they call | |
| 262 // drawPath on SkGpuDevice | |
| 263 GrContext* context = reinterpret_cast<GrContext*>(data); | |
| 264 context->flush(); | |
| 265 } | |
| 266 | |
| 267 int GrContext::getMaxTextureSize() const { | |
| 268 return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride); | |
| 269 } | |
| 270 | |
| 271 int GrContext::getMaxRenderTargetSize() const { | |
| 272 return fGpu->caps()->maxRenderTargetSize(); | |
| 273 } | |
| 274 | |
| 275 int GrContext::getMaxSampleCount() const { | |
| 276 return fGpu->caps()->maxSampleCount(); | |
| 277 } | |
| 278 | |
| 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 | 95 RETURN_IF_ABANDONED |
| 303 // set rect to be big enough to fill the space, but not super-huge, so we | 96 // set rect to be big enough to fill the space, but not super-huge, so we |
| 304 // don't overflow fixed-point implementations | 97 // don't overflow fixed-point implementations |
| 305 SkRect r; | 98 SkRect r; |
| 306 r.setLTRB(0, 0, | 99 r.setLTRB(0, 0, |
| 307 SkIntToScalar(rt->width()), | 100 SkIntToScalar(rt->width()), |
| 308 SkIntToScalar(rt->height())); | 101 SkIntToScalar(rt->height())); |
| 309 SkTCopyOnFirstWrite<GrPaint> paint(origPaint); | 102 SkTCopyOnFirstWrite<GrPaint> paint(origPaint); |
| 310 | 103 |
| 311 // by definition this fills the entire clip, no need for AA | 104 // by definition this fills the entire clip, no need for AA |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 326 } | 119 } |
| 327 inverse.mapRect(&r); | 120 inverse.mapRect(&r); |
| 328 this->drawRect(rt, clip, *paint, viewMatrix, r); | 121 this->drawRect(rt, clip, *paint, viewMatrix, r); |
| 329 } else { | 122 } else { |
| 330 SkMatrix localMatrix; | 123 SkMatrix localMatrix; |
| 331 if (!viewMatrix.invert(&localMatrix)) { | 124 if (!viewMatrix.invert(&localMatrix)) { |
| 332 SkDebugf("Could not invert matrix\n"); | 125 SkDebugf("Could not invert matrix\n"); |
| 333 return; | 126 return; |
| 334 } | 127 } |
| 335 | 128 |
| 336 AutoCheckFlush acf(this); | 129 AutoCheckFlush acf(fContext); |
| 337 GrPipelineBuilder pipelineBuilder; | 130 GrPipelineBuilder pipelineBuilder; |
| 338 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, p aint, &acf); | 131 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, paint)) { |
| 339 if (NULL == target) { | |
| 340 return; | 132 return; |
| 341 } | 133 } |
| 342 | 134 |
| 343 GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target); | 135 GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawContext::drawPaint", fContext); |
|
bsalomon
2015/05/22 20:33:58
Let's delete these
robertphillips
2015/05/26 16:12:58
Done.
| |
| 344 target->drawRect(&pipelineBuilder, | 136 fDrawTarget->drawBWRect(&pipelineBuilder, |
| 345 paint->getColor(), | 137 paint->getColor(), |
| 346 SkMatrix::I(), | 138 SkMatrix::I(), |
| 347 r, | 139 r, |
| 348 NULL, | 140 NULL, |
| 349 &localMatrix); | 141 &localMatrix); |
| 350 } | 142 } |
| 351 } | 143 } |
| 352 | 144 |
| 353 //////////////////////////////////////////////////////////////////////////////// | |
| 354 | |
| 355 static inline bool is_irect(const SkRect& r) { | 145 static inline bool is_irect(const SkRect& r) { |
| 356 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) && | 146 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) && |
| 357 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom); | 147 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom); |
| 358 } | 148 } |
| 359 | 149 |
| 360 static bool apply_aa_to_rect(GrDrawTarget* target, | 150 static bool apply_aa_to_rect(GrDrawTarget* target, |
| 361 GrPipelineBuilder* pipelineBuilder, | 151 GrPipelineBuilder* pipelineBuilder, |
| 362 SkRect* devBoundRect, | 152 SkRect* devBoundRect, |
| 363 const SkRect& rect, | 153 const SkRect& rect, |
| 364 SkScalar strokeWidth, | 154 SkScalar strokeWidth, |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 564 bool fHairline; | 354 bool fHairline; |
| 565 }; | 355 }; |
| 566 | 356 |
| 567 const static int kVertsPerHairlineRect = 5; | 357 const static int kVertsPerHairlineRect = 5; |
| 568 const static int kVertsPerStrokeRect = 10; | 358 const static int kVertsPerStrokeRect = 10; |
| 569 | 359 |
| 570 BatchTracker fBatch; | 360 BatchTracker fBatch; |
| 571 SkSTArray<1, Geometry, true> fGeoData; | 361 SkSTArray<1, Geometry, true> fGeoData; |
| 572 }; | 362 }; |
| 573 | 363 |
| 574 void GrContext::drawRect(GrRenderTarget* rt, | 364 void GrDrawContext::drawRect(GrRenderTarget* rt, |
| 575 const GrClip& clip, | 365 const GrClip& clip, |
| 576 const GrPaint& paint, | 366 const GrPaint& paint, |
| 577 const SkMatrix& viewMatrix, | 367 const SkMatrix& viewMatrix, |
| 578 const SkRect& rect, | 368 const SkRect& rect, |
| 579 const GrStrokeInfo* strokeInfo) { | 369 const GrStrokeInfo* strokeInfo) { |
| 580 RETURN_IF_ABANDONED | 370 RETURN_IF_ABANDONED |
| 581 if (strokeInfo && strokeInfo->isDashed()) { | 371 if (strokeInfo && strokeInfo->isDashed()) { |
| 582 SkPath path; | 372 SkPath path; |
| 583 path.setIsVolatile(true); | 373 path.setIsVolatile(true); |
| 584 path.addRect(rect); | 374 path.addRect(rect); |
| 585 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo); | 375 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo); |
| 586 return; | 376 return; |
| 587 } | 377 } |
| 588 | 378 |
| 589 AutoCheckFlush acf(this); | 379 AutoCheckFlush acf(fContext); |
| 590 GrPipelineBuilder pipelineBuilder; | 380 GrPipelineBuilder pipelineBuilder; |
| 591 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain t, &acf); | 381 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
| 592 if (NULL == target) { | |
| 593 return; | 382 return; |
| 594 } | 383 } |
| 595 | 384 |
| 596 GR_CREATE_TRACE_MARKER("GrContext::drawRect", target); | 385 GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawContext::drawRect", fContext); |
| 597 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth(); | 386 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth(); |
| 598 | 387 |
| 599 // Check if this is a full RT draw and can be replaced with a clear. We don' t bother checking | 388 // 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. | 389 // cases where the RT is fully inside a stroke. |
| 601 if (width < 0) { | 390 if (width < 0) { |
| 602 SkRect rtRect; | 391 SkRect rtRect; |
| 603 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect); | 392 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect); |
| 604 SkRect clipSpaceRTRect = rtRect; | 393 SkRect clipSpaceRTRect = rtRect; |
| 605 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType(); | 394 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType(); |
| 606 if (checkClip) { | 395 if (checkClip) { |
| 607 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX), | 396 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX), |
| 608 SkIntToScalar(clip.origin().fY)); | 397 SkIntToScalar(clip.origin().fY)); |
| 609 } | 398 } |
| 610 // Does the clip contain the entire RT? | 399 // Does the clip contain the entire RT? |
| 611 if (!checkClip || clip.quickContains(clipSpaceRTRect)) { | 400 if (!checkClip || clip.quickContains(clipSpaceRTRect)) { |
| 612 SkMatrix invM; | 401 SkMatrix invM; |
| 613 if (!viewMatrix.invert(&invM)) { | 402 if (!viewMatrix.invert(&invM)) { |
| 614 return; | 403 return; |
| 615 } | 404 } |
| 616 // Does the rect bound the RT? | 405 // Does the rect bound the RT? |
| 617 SkPoint srcSpaceRTQuad[4]; | 406 SkPoint srcSpaceRTQuad[4]; |
| 618 invM.mapRectToQuad(srcSpaceRTQuad, rtRect); | 407 invM.mapRectToQuad(srcSpaceRTQuad, rtRect); |
| 619 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) && | 408 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) && |
| 620 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) && | 409 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) && |
| 621 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) && | 410 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) && |
| 622 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) { | 411 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) { |
| 623 // Will it blend? | 412 // Will it blend? |
| 624 GrColor clearColor; | 413 GrColor clearColor; |
| 625 if (paint.isOpaqueAndConstantColor(&clearColor)) { | 414 if (paint.isOpaqueAndConstantColor(&clearColor)) { |
| 626 target->clear(NULL, clearColor, true, rt); | 415 fDrawTarget->clear(NULL, clearColor, true, rt); |
| 627 return; | 416 return; |
| 628 } | 417 } |
| 629 } | 418 } |
| 630 } | 419 } |
| 631 } | 420 } |
| 632 | 421 |
| 633 GrColor color = paint.getColor(); | 422 GrColor color = paint.getColor(); |
| 634 SkRect devBoundRect; | 423 SkRect devBoundRect; |
| 635 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isM ultisampled(); | 424 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isM ultisampled(); |
| 636 bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRe ct, rect, width, | 425 bool doAA = needAA && apply_aa_to_rect(fDrawTarget, &pipelineBuilder, &devBo undRect, rect, |
| 637 viewMatrix, color); | 426 width, viewMatrix, color); |
| 638 | 427 |
| 639 if (doAA) { | 428 if (doAA) { |
| 640 if (width >= 0) { | 429 if (width >= 0) { |
| 641 fAARectRenderer->strokeAARect(target, | 430 GrAARectRenderer::StrokeAARect(fDrawTarget, |
| 642 &pipelineBuilder, | 431 &pipelineBuilder, |
| 643 color, | 432 color, |
| 644 viewMatrix, | 433 viewMatrix, |
| 645 rect, | 434 rect, |
| 646 devBoundRect, | 435 devBoundRect, |
| 647 *strokeInfo); | 436 *strokeInfo); |
| 648 } else { | 437 } else { |
| 649 // filled AA rect | 438 // filled AA rect |
| 650 fAARectRenderer->fillAARect(target, | 439 GrAARectRenderer::FillAARect(fDrawTarget, |
| 651 &pipelineBuilder, | 440 &pipelineBuilder, |
| 652 color, | 441 color, |
| 653 viewMatrix, | 442 viewMatrix, |
| 654 rect, | 443 rect, |
| 655 devBoundRect); | 444 devBoundRect); |
| 656 } | 445 } |
| 657 return; | 446 return; |
| 658 } | 447 } |
| 659 | 448 |
| 660 if (width >= 0) { | 449 if (width >= 0) { |
| 661 StrokeRectBatch::Geometry geometry; | 450 StrokeRectBatch::Geometry geometry; |
| 662 geometry.fViewMatrix = viewMatrix; | 451 geometry.fViewMatrix = viewMatrix; |
| 663 geometry.fColor = color; | 452 geometry.fColor = color; |
| 664 geometry.fRect = rect; | 453 geometry.fRect = rect; |
| 665 geometry.fStrokeWidth = width; | 454 geometry.fStrokeWidth = width; |
| 666 | 455 |
| 667 // Non-AA hairlines are snapped to pixel centers to make which pixels ar e hit deterministic | 456 // Non-AA hairlines are snapped to pixel centers to make which pixels ar e hit deterministic |
| 668 bool snapToPixelCenters = (0 == width && !rt->isMultisampled()); | 457 bool snapToPixelCenters = (0 == width && !rt->isMultisampled()); |
| 669 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixe lCenters)); | 458 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixe lCenters)); |
| 670 | 459 |
| 671 // Depending on sub-pixel coordinates and the particular GPU, we may los e a corner of | 460 // 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 | 461 // 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. | 462 // is enabled because it can cause ugly artifacts. |
| 674 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_ Flag, | 463 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_ Flag, |
| 675 snapToPixelCenters); | 464 snapToPixelCenters); |
| 676 target->drawBatch(&pipelineBuilder, batch); | 465 fDrawTarget->drawBatch(&pipelineBuilder, batch); |
| 677 } else { | 466 } else { |
| 678 // filled BW rect | 467 // filled BW rect |
| 679 target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect); | 468 fDrawTarget->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect); |
| 680 } | 469 } |
| 681 } | 470 } |
| 682 | 471 |
| 683 void GrContext::drawNonAARectToRect(GrRenderTarget* rt, | 472 void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt, |
| 684 const GrClip& clip, | 473 const GrClip& clip, |
| 685 const GrPaint& paint, | 474 const GrPaint& paint, |
| 686 const SkMatrix& viewMatrix, | 475 const SkMatrix& viewMatrix, |
| 687 const SkRect& rectToDraw, | 476 const SkRect& rectToDraw, |
| 688 const SkRect& localRect, | 477 const SkRect& localRect, |
| 689 const SkMatrix* localMatrix) { | 478 const SkMatrix* localMatrix) { |
| 690 RETURN_IF_ABANDONED | 479 RETURN_IF_ABANDONED |
| 691 AutoCheckFlush acf(this); | 480 AutoCheckFlush acf(fContext); |
| 692 GrPipelineBuilder pipelineBuilder; | 481 GrPipelineBuilder pipelineBuilder; |
| 693 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain t, &acf); | 482 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
| 694 if (NULL == target) { | |
| 695 return; | 483 return; |
| 696 } | 484 } |
| 697 | 485 |
| 698 GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target); | 486 GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawContext::drawRectToRect", fContext); |
| 699 | 487 |
| 700 target->drawRect(&pipelineBuilder, | 488 fDrawTarget->drawBWRect(&pipelineBuilder, |
| 701 paint.getColor(), | 489 paint.getColor(), |
| 702 viewMatrix, | 490 viewMatrix, |
| 703 rectToDraw, | 491 rectToDraw, |
| 704 &localRect, | 492 &localRect, |
| 705 localMatrix); | 493 localMatrix); |
| 706 } | 494 } |
| 707 | 495 |
| 708 static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords, | 496 static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords, |
| 709 bool hasColors, | 497 bool hasColors, |
| 710 int* colorOffset, | 498 int* colorOffset, |
| 711 int* texOffset, | 499 int* texOffset, |
| 712 GrColor color, | 500 GrColor color, |
| 713 const SkMatrix& viewMatr ix, | 501 const SkMatrix& viewMatr ix, |
| 714 bool coverageIgnored) { | 502 bool coverageIgnored) { |
| 715 *texOffset = -1; | 503 *texOffset = -1; |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 969 bool fHasIndices; | 757 bool fHasIndices; |
| 970 bool fHasLocalCoords; | 758 bool fHasLocalCoords; |
| 971 int fVertexCount; | 759 int fVertexCount; |
| 972 int fIndexCount; | 760 int fIndexCount; |
| 973 }; | 761 }; |
| 974 | 762 |
| 975 BatchTracker fBatch; | 763 BatchTracker fBatch; |
| 976 SkSTArray<1, Geometry, true> fGeoData; | 764 SkSTArray<1, Geometry, true> fGeoData; |
| 977 }; | 765 }; |
| 978 | 766 |
| 979 void GrContext::drawVertices(GrRenderTarget* rt, | 767 void GrDrawContext::drawVertices(GrRenderTarget* rt, |
| 980 const GrClip& clip, | 768 const GrClip& clip, |
| 981 const GrPaint& paint, | 769 const GrPaint& paint, |
| 982 const SkMatrix& viewMatrix, | 770 const SkMatrix& viewMatrix, |
| 983 GrPrimitiveType primitiveType, | 771 GrPrimitiveType primitiveType, |
| 984 int vertexCount, | 772 int vertexCount, |
| 985 const SkPoint positions[], | 773 const SkPoint positions[], |
| 986 const SkPoint texCoords[], | 774 const SkPoint texCoords[], |
| 987 const GrColor colors[], | 775 const GrColor colors[], |
| 988 const uint16_t indices[], | 776 const uint16_t indices[], |
| 989 int indexCount) { | 777 int indexCount) { |
| 990 RETURN_IF_ABANDONED | 778 RETURN_IF_ABANDONED |
| 991 AutoCheckFlush acf(this); | 779 AutoCheckFlush acf(fContext); |
| 992 GrPipelineBuilder pipelineBuilder; | 780 GrPipelineBuilder pipelineBuilder; |
| 993 | 781 |
| 994 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain t, &acf); | 782 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
| 995 if (NULL == target) { | |
| 996 return; | 783 return; |
| 997 } | 784 } |
| 998 | 785 |
| 999 GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target); | 786 GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawContext::drawVertices", fContext); |
| 1000 | 787 |
| 1001 // TODO clients should give us bounds | 788 // TODO clients should give us bounds |
| 1002 SkRect bounds; | 789 SkRect bounds; |
| 1003 if (!bounds.setBoundsCheck(positions, vertexCount)) { | 790 if (!bounds.setBoundsCheck(positions, vertexCount)) { |
| 1004 SkDebugf("drawVertices call empty bounds\n"); | 791 SkDebugf("drawVertices call empty bounds\n"); |
| 1005 return; | 792 return; |
| 1006 } | 793 } |
| 1007 | 794 |
| 1008 viewMatrix.mapRect(&bounds); | 795 viewMatrix.mapRect(&bounds); |
| 1009 | 796 |
| 1010 // If we don't have AA then we outset for a half pixel in each direction to account for | 797 // If we don't have AA then we outset for a half pixel in each direction to account for |
| 1011 // snapping | 798 // snapping |
| 1012 if (!paint.isAntiAlias()) { | 799 if (!paint.isAntiAlias()) { |
| 1013 bounds.outset(0.5f, 0.5f); | 800 bounds.outset(0.5f, 0.5f); |
| 1014 } | 801 } |
| 1015 | 802 |
| 1016 DrawVerticesBatch::Geometry geometry; | 803 DrawVerticesBatch::Geometry geometry; |
| 1017 geometry.fColor = paint.getColor(); | 804 geometry.fColor = paint.getColor(); |
| 1018 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveTyp e, viewMatrix, | 805 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveTyp e, viewMatrix, |
| 1019 positions, vertexCount , indices, | 806 positions, vertexCount , indices, |
| 1020 indexCount, colors, te xCoords, | 807 indexCount, colors, te xCoords, |
| 1021 bounds)); | 808 bounds)); |
| 1022 | 809 |
| 1023 target->drawBatch(&pipelineBuilder, batch); | 810 fDrawTarget->drawBatch(&pipelineBuilder, batch); |
| 1024 } | 811 } |
| 1025 | 812 |
| 1026 /////////////////////////////////////////////////////////////////////////////// | 813 /////////////////////////////////////////////////////////////////////////////// |
| 1027 | 814 |
| 1028 void GrContext::drawRRect(GrRenderTarget*rt, | 815 void GrDrawContext::drawRRect(GrRenderTarget*rt, |
| 1029 const GrClip& clip, | 816 const GrClip& clip, |
| 1030 const GrPaint& paint, | 817 const GrPaint& paint, |
| 1031 const SkMatrix& viewMatrix, | 818 const SkMatrix& viewMatrix, |
| 1032 const SkRRect& rrect, | 819 const SkRRect& rrect, |
| 1033 const GrStrokeInfo& strokeInfo) { | 820 const GrStrokeInfo& strokeInfo) { |
| 1034 RETURN_IF_ABANDONED | 821 RETURN_IF_ABANDONED |
| 1035 if (rrect.isEmpty()) { | 822 if (rrect.isEmpty()) { |
| 1036 return; | 823 return; |
| 1037 } | 824 } |
| 1038 | 825 |
| 1039 if (strokeInfo.isDashed()) { | 826 if (strokeInfo.isDashed()) { |
| 1040 SkPath path; | 827 SkPath path; |
| 1041 path.setIsVolatile(true); | 828 path.setIsVolatile(true); |
| 1042 path.addRRect(rrect); | 829 path.addRRect(rrect); |
| 1043 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); | 830 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); |
| 1044 return; | 831 return; |
| 1045 } | 832 } |
| 1046 | 833 |
| 1047 AutoCheckFlush acf(this); | 834 AutoCheckFlush acf(fContext); |
| 1048 GrPipelineBuilder pipelineBuilder; | 835 GrPipelineBuilder pipelineBuilder; |
| 1049 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain t, &acf); | 836 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
| 1050 if (NULL == target) { | |
| 1051 return; | 837 return; |
| 1052 } | 838 } |
| 1053 | 839 |
| 1054 GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target); | 840 GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawContext::drawRRect", fContext); |
| 1055 | 841 |
| 1056 GrColor color = paint.getColor(); | 842 GrColor color = paint.getColor(); |
| 1057 if (!fOvalRenderer->drawRRect(target, | 843 if (!GrOvalRenderer::DrawRRect(fDrawTarget, |
| 1058 &pipelineBuilder, | 844 &pipelineBuilder, |
| 1059 color, | 845 color, |
| 1060 viewMatrix, | 846 viewMatrix, |
| 1061 paint.isAntiAlias(), | 847 paint.isAntiAlias(), |
| 1062 rrect, | 848 rrect, |
| 1063 strokeInfo)) { | 849 strokeInfo)) { |
| 1064 SkPath path; | 850 SkPath path; |
| 1065 path.setIsVolatile(true); | 851 path.setIsVolatile(true); |
| 1066 path.addRRect(rrect); | 852 path.addRRect(rrect); |
| 1067 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain t.isAntiAlias(), | 853 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, |
| 1068 path, strokeInfo); | 854 paint.isAntiAlias(), path, strokeInfo); |
| 1069 } | 855 } |
| 1070 } | 856 } |
| 1071 | 857 |
| 1072 /////////////////////////////////////////////////////////////////////////////// | 858 /////////////////////////////////////////////////////////////////////////////// |
| 1073 | 859 |
| 1074 void GrContext::drawDRRect(GrRenderTarget* rt, | 860 void GrDrawContext::drawDRRect(GrRenderTarget* rt, |
| 1075 const GrClip& clip, | 861 const GrClip& clip, |
| 1076 const GrPaint& paint, | 862 const GrPaint& paint, |
| 1077 const SkMatrix& viewMatrix, | 863 const SkMatrix& viewMatrix, |
| 1078 const SkRRect& outer, | 864 const SkRRect& outer, |
| 1079 const SkRRect& inner) { | 865 const SkRRect& inner) { |
| 1080 RETURN_IF_ABANDONED | 866 RETURN_IF_ABANDONED |
| 1081 if (outer.isEmpty()) { | 867 if (outer.isEmpty()) { |
| 1082 return; | 868 return; |
| 1083 } | 869 } |
| 1084 | 870 |
| 1085 AutoCheckFlush acf(this); | 871 AutoCheckFlush acf(fContext); |
| 1086 GrPipelineBuilder pipelineBuilder; | 872 GrPipelineBuilder pipelineBuilder; |
| 1087 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain t, &acf); | 873 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
| 874 return; | |
| 875 } | |
| 1088 | 876 |
| 1089 GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target); | 877 GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::drawDRRect", fContext); |
| 1090 | 878 |
| 1091 GrColor color = paint.getColor(); | 879 GrColor color = paint.getColor(); |
| 1092 if (!fOvalRenderer->drawDRRect(target, | 880 if (!GrOvalRenderer::DrawDRRect(fDrawTarget, |
| 1093 &pipelineBuilder, | 881 &pipelineBuilder, |
| 1094 color, | 882 color, |
| 1095 viewMatrix, | 883 viewMatrix, |
| 1096 paint.isAntiAlias(), | 884 paint.isAntiAlias(), |
| 1097 outer, | 885 outer, |
| 1098 inner)) { | 886 inner)) { |
| 1099 SkPath path; | 887 SkPath path; |
| 1100 path.setIsVolatile(true); | 888 path.setIsVolatile(true); |
| 1101 path.addRRect(inner); | 889 path.addRRect(inner); |
| 1102 path.addRRect(outer); | 890 path.addRRect(outer); |
| 1103 path.setFillType(SkPath::kEvenOdd_FillType); | 891 path.setFillType(SkPath::kEvenOdd_FillType); |
| 892 | |
| 1104 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle); | 893 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle); |
| 1105 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain t.isAntiAlias(), | 894 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, |
| 1106 path, fillRec); | 895 paint.isAntiAlias(), path, fillRec); |
| 1107 } | 896 } |
| 1108 } | 897 } |
| 1109 | 898 |
| 1110 /////////////////////////////////////////////////////////////////////////////// | 899 /////////////////////////////////////////////////////////////////////////////// |
| 1111 | 900 |
| 1112 void GrContext::drawOval(GrRenderTarget* rt, | 901 void GrDrawContext::drawOval(GrRenderTarget* rt, |
| 1113 const GrClip& clip, | 902 const GrClip& clip, |
| 1114 const GrPaint& paint, | 903 const GrPaint& paint, |
| 1115 const SkMatrix& viewMatrix, | 904 const SkMatrix& viewMatrix, |
| 1116 const SkRect& oval, | 905 const SkRect& oval, |
| 1117 const GrStrokeInfo& strokeInfo) { | 906 const GrStrokeInfo& strokeInfo) { |
| 1118 RETURN_IF_ABANDONED | 907 RETURN_IF_ABANDONED |
| 1119 if (oval.isEmpty()) { | 908 if (oval.isEmpty()) { |
| 1120 return; | 909 return; |
| 1121 } | 910 } |
| 1122 | 911 |
| 1123 if (strokeInfo.isDashed()) { | 912 if (strokeInfo.isDashed()) { |
| 1124 SkPath path; | 913 SkPath path; |
| 1125 path.setIsVolatile(true); | 914 path.setIsVolatile(true); |
| 1126 path.addOval(oval); | 915 path.addOval(oval); |
| 1127 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); | 916 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo); |
| 1128 return; | 917 return; |
| 1129 } | 918 } |
| 1130 | 919 |
| 1131 AutoCheckFlush acf(this); | 920 AutoCheckFlush acf(fContext); |
| 1132 GrPipelineBuilder pipelineBuilder; | 921 GrPipelineBuilder pipelineBuilder; |
| 1133 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain t, &acf); | 922 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
| 1134 if (NULL == target) { | |
| 1135 return; | 923 return; |
| 1136 } | 924 } |
| 1137 | 925 |
| 1138 GR_CREATE_TRACE_MARKER("GrContext::drawOval", target); | 926 GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawContext::drawOval", fContext); |
| 1139 | 927 |
| 1140 GrColor color = paint.getColor(); | 928 GrColor color = paint.getColor(); |
| 1141 if (!fOvalRenderer->drawOval(target, | 929 if (!GrOvalRenderer::DrawOval(fDrawTarget, |
| 1142 &pipelineBuilder, | 930 &pipelineBuilder, |
| 1143 color, | 931 color, |
| 1144 viewMatrix, | 932 viewMatrix, |
| 1145 paint.isAntiAlias(), | 933 paint.isAntiAlias(), |
| 1146 oval, | 934 oval, |
| 1147 strokeInfo)) { | 935 strokeInfo)) { |
| 1148 SkPath path; | 936 SkPath path; |
| 1149 path.setIsVolatile(true); | 937 path.setIsVolatile(true); |
| 1150 path.addOval(oval); | 938 path.addOval(oval); |
| 1151 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, pain t.isAntiAlias(), | 939 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, |
| 1152 path, strokeInfo); | 940 paint.isAntiAlias(), path, strokeInfo); |
| 1153 } | 941 } |
| 1154 } | 942 } |
| 1155 | 943 |
| 1156 // Can 'path' be drawn as a pair of filled nested rectangles? | 944 // Can 'path' be drawn as a pair of filled nested rectangles? |
| 1157 static bool is_nested_rects(GrDrawTarget* target, | 945 static bool is_nested_rects(GrDrawTarget* target, |
| 1158 GrPipelineBuilder* pipelineBuilder, | 946 GrPipelineBuilder* pipelineBuilder, |
| 1159 GrColor color, | 947 GrColor color, |
| 1160 const SkMatrix& viewMatrix, | 948 const SkMatrix& viewMatrix, |
| 1161 const SkPath& path, | 949 const SkPath& path, |
| 1162 const SkStrokeRec& stroke, | 950 const SkStrokeRec& stroke, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1199 allGoE1 = false; | 987 allGoE1 = false; |
| 1200 } | 988 } |
| 1201 if (!SkScalarNearlyEqual(margin, temp)) { | 989 if (!SkScalarNearlyEqual(margin, temp)) { |
| 1202 allEq = false; | 990 allEq = false; |
| 1203 } | 991 } |
| 1204 } | 992 } |
| 1205 | 993 |
| 1206 return allEq || allGoE1; | 994 return allEq || allGoE1; |
| 1207 } | 995 } |
| 1208 | 996 |
| 1209 void GrContext::drawPath(GrRenderTarget* rt, | 997 void GrDrawContext::drawPath(GrRenderTarget* rt, |
| 1210 const GrClip& clip, | 998 const GrClip& clip, |
| 1211 const GrPaint& paint, | 999 const GrPaint& paint, |
| 1212 const SkMatrix& viewMatrix, | 1000 const SkMatrix& viewMatrix, |
| 1213 const SkPath& path, | 1001 const SkPath& path, |
| 1214 const GrStrokeInfo& strokeInfo) { | 1002 const GrStrokeInfo& strokeInfo) { |
| 1215 RETURN_IF_ABANDONED | 1003 RETURN_IF_ABANDONED |
| 1216 if (path.isEmpty()) { | 1004 if (path.isEmpty()) { |
| 1217 if (path.isInverseFillType()) { | 1005 if (path.isInverseFillType()) { |
| 1218 this->drawPaint(rt, clip, paint, viewMatrix); | 1006 this->drawPaint(rt, clip, paint, viewMatrix); |
| 1219 } | 1007 } |
| 1220 return; | 1008 return; |
| 1221 } | 1009 } |
| 1222 | 1010 |
| 1223 GrColor color = paint.getColor(); | 1011 GrColor color = paint.getColor(); |
| 1224 | 1012 |
| 1225 // Note that internalDrawPath may sw-rasterize the path into a scratch textu re. | 1013 // 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 | 1014 // Scratch textures can be recycled after they are returned to the texture |
| 1227 // cache. This presents a potential hazard for buffered drawing. However, | 1015 // 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 | 1016 // the writePixels that uploads to the scratch will perform a flush so we're |
| 1229 // OK. | 1017 // OK. |
| 1230 AutoCheckFlush acf(this); | 1018 AutoCheckFlush acf(fContext); |
| 1231 GrPipelineBuilder pipelineBuilder; | 1019 GrPipelineBuilder pipelineBuilder; |
| 1232 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &pain t, &acf); | 1020 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) { |
| 1233 if (NULL == target) { | |
| 1234 return; | 1021 return; |
| 1235 } | 1022 } |
| 1236 | 1023 |
| 1237 GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isC onvex()); | 1024 GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawContext::drawPath", fContext); |
| 1238 | 1025 |
| 1239 if (!strokeInfo.isDashed()) { | 1026 if (!strokeInfo.isDashed()) { |
| 1240 bool useCoverageAA = paint.isAntiAlias() && | 1027 bool useCoverageAA = paint.isAntiAlias() && |
| 1241 !pipelineBuilder.getRenderTarget()->isMultisampled(); | 1028 !pipelineBuilder.getRenderTarget()->isMultisampled(); |
| 1242 | 1029 |
| 1243 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) { | 1030 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) { |
| 1244 // Concave AA paths are expensive - try to avoid them for special ca ses | 1031 // Concave AA paths are expensive - try to avoid them for special ca ses |
| 1245 SkRect rects[2]; | 1032 SkRect rects[2]; |
| 1246 | 1033 |
| 1247 if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, pat h, strokeInfo, | 1034 if (is_nested_rects(fDrawTarget, &pipelineBuilder, color, viewMatrix , path, strokeInfo, |
| 1248 rects)) { | 1035 rects)) { |
| 1249 fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, col or, viewMatrix, | 1036 GrAARectRenderer::FillAANestedRects(fDrawTarget, &pipelineBuilde r, color, |
| 1250 rects); | 1037 viewMatrix, rects); |
| 1251 return; | 1038 return; |
| 1252 } | 1039 } |
| 1253 } | 1040 } |
| 1254 SkRect ovalRect; | 1041 SkRect ovalRect; |
| 1255 bool isOval = path.isOval(&ovalRect); | 1042 bool isOval = path.isOval(&ovalRect); |
| 1256 | 1043 |
| 1257 if (isOval && !path.isInverseFillType()) { | 1044 if (isOval && !path.isInverseFillType()) { |
| 1258 if (fOvalRenderer->drawOval(target, | 1045 if (GrOvalRenderer::DrawOval(fDrawTarget, |
| 1259 &pipelineBuilder, | 1046 &pipelineBuilder, |
| 1260 color, | 1047 color, |
| 1261 viewMatrix, | 1048 viewMatrix, |
| 1262 paint.isAntiAlias(), | 1049 paint.isAntiAlias(), |
| 1263 ovalRect, | 1050 ovalRect, |
| 1264 strokeInfo)) { | 1051 strokeInfo)) { |
| 1265 return; | 1052 return; |
| 1266 } | 1053 } |
| 1267 } | 1054 } |
| 1268 } | 1055 } |
| 1269 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.is AntiAlias(), | 1056 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, pai nt.isAntiAlias(), |
| 1270 path, strokeInfo); | 1057 path, strokeInfo); |
| 1271 } | 1058 } |
| 1272 | 1059 |
| 1273 void GrContext::internalDrawPath(GrDrawTarget* target, | 1060 void GrDrawContext::internalDrawPath(GrDrawTarget* target, |
| 1274 GrPipelineBuilder* pipelineBuilder, | 1061 GrPipelineBuilder* pipelineBuilder, |
| 1275 const SkMatrix& viewMatrix, | 1062 const SkMatrix& viewMatrix, |
| 1276 GrColor color, | 1063 GrColor color, |
| 1277 bool useAA, | 1064 bool useAA, |
| 1278 const SkPath& path, | 1065 const SkPath& path, |
| 1279 const GrStrokeInfo& strokeInfo) { | 1066 const GrStrokeInfo& strokeInfo) { |
| 1280 RETURN_IF_ABANDONED | 1067 RETURN_IF_ABANDONED |
| 1281 SkASSERT(!path.isEmpty()); | 1068 SkASSERT(!path.isEmpty()); |
| 1282 | 1069 |
| 1283 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target); | 1070 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target); |
| 1284 | 1071 |
| 1285 | 1072 |
| 1286 // An Assumption here is that path renderer would use some form of tweaking | 1073 // 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 | 1074 // 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 | 1075 // 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. | 1076 // thing WRT to the blend then we'll need some query on the PR. |
| 1290 bool useCoverageAA = useAA && | 1077 bool useCoverageAA = useAA && |
| 1291 !pipelineBuilder->getRenderTarget()->isMultisampled(); | 1078 !pipelineBuilder->getRenderTarget()->isMultisampled(); |
| 1292 | 1079 |
| 1293 | 1080 |
| 1294 GrPathRendererChain::DrawType type = | 1081 GrPathRendererChain::DrawType type = |
| 1295 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType : | 1082 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType : |
| 1296 GrPathRendererChain::kColor_DrawType; | 1083 GrPathRendererChain::kColor_DrawType; |
| 1297 | 1084 |
| 1298 const SkPath* pathPtr = &path; | 1085 const SkPath* pathPtr = &path; |
| 1299 SkTLazy<SkPath> tmpPath; | 1086 SkTLazy<SkPath> tmpPath; |
| 1300 const GrStrokeInfo* strokeInfoPtr = &strokeInfo; | 1087 const GrStrokeInfo* strokeInfoPtr = &strokeInfo; |
| 1301 | 1088 |
| 1302 // Try a 1st time without stroking the path and without allowing the SW rend erer | 1089 // 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, | 1090 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, view Matrix, *pathPtr, |
| 1304 *strokeInfoPtr, false, type); | 1091 *strokeInfoPtr, false, type) ; |
| 1305 | 1092 |
| 1306 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false); | 1093 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false); |
| 1307 if (NULL == pr && strokeInfo.isDashed()) { | 1094 if (NULL == pr && strokeInfo.isDashed()) { |
| 1308 // It didn't work above, so try again with dashed stroke converted to a dashless stroke. | 1095 // 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)) { | 1096 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pa thPtr)) { |
| 1310 return; | 1097 return; |
| 1311 } | 1098 } |
| 1312 pathPtr = tmpPath.get(); | 1099 pathPtr = tmpPath.get(); |
| 1313 if (pathPtr->isEmpty()) { | 1100 if (pathPtr->isEmpty()) { |
| 1314 return; | 1101 return; |
| 1315 } | 1102 } |
| 1316 strokeInfoPtr = &dashlessStrokeInfo; | 1103 strokeInfoPtr = &dashlessStrokeInfo; |
| 1317 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr , *strokeInfoPtr, | 1104 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pat hPtr, *strokeInfoPtr, |
| 1318 false, type); | 1105 false, type); |
| 1319 } | 1106 } |
| 1320 | 1107 |
| 1321 if (NULL == pr) { | 1108 if (NULL == pr) { |
| 1322 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMa trix, NULL) && | 1109 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMa trix, NULL) && |
| 1323 !strokeInfoPtr->isFillStyle()) { | 1110 !strokeInfoPtr->isFillStyle()) { |
| 1324 // It didn't work above, so try again with stroke converted to a fil l. | 1111 // It didn't work above, so try again with stroke converted to a fil l. |
| 1325 if (!tmpPath.isValid()) { | 1112 if (!tmpPath.isValid()) { |
| 1326 tmpPath.init(); | 1113 tmpPath.init(); |
| 1327 } | 1114 } |
| 1328 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()) ); | 1115 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()) ); |
| 1329 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) { | 1116 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) { |
| 1330 return; | 1117 return; |
| 1331 } | 1118 } |
| 1332 pathPtr = tmpPath.get(); | 1119 pathPtr = tmpPath.get(); |
| 1333 if (pathPtr->isEmpty()) { | 1120 if (pathPtr->isEmpty()) { |
| 1334 return; | 1121 return; |
| 1335 } | 1122 } |
| 1336 dashlessStrokeInfo.setFillStyle(); | 1123 dashlessStrokeInfo.setFillStyle(); |
| 1337 strokeInfoPtr = &dashlessStrokeInfo; | 1124 strokeInfoPtr = &dashlessStrokeInfo; |
| 1338 } | 1125 } |
| 1339 | 1126 |
| 1340 // This time, allow SW renderer | 1127 // This time, allow SW renderer |
| 1341 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr , *strokeInfoPtr, | 1128 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pat hPtr, *strokeInfoPtr, |
| 1342 true, type); | 1129 true, type); |
| 1343 } | 1130 } |
| 1344 | 1131 |
| 1345 if (NULL == pr) { | 1132 if (NULL == pr) { |
| 1346 #ifdef SK_DEBUG | 1133 #ifdef SK_DEBUG |
| 1347 SkDebugf("Unable to find path renderer compatible with path.\n"); | 1134 SkDebugf("Unable to find path renderer compatible with path.\n"); |
| 1348 #endif | 1135 #endif |
| 1349 return; | 1136 return; |
| 1350 } | 1137 } |
| 1351 | 1138 |
| 1352 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeIn foPtr, useCoverageAA); | 1139 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeIn foPtr, useCoverageAA); |
| 1353 } | 1140 } |
| 1354 | 1141 |
| 1355 //////////////////////////////////////////////////////////////////////////////// | 1142 bool GrDrawContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder, |
| 1143 GrRenderTarget* rt, | |
| 1144 const GrClip& clip, | |
| 1145 const GrPaint* paint) { | |
| 1146 RETURN_FALSE_IF_ABANDONED | |
| 1356 | 1147 |
| 1357 void GrContext::flush(int flagsBitfield) { | 1148 ASSERT_OWNED_RESOURCE(rt); |
| 1358 if (NULL == fDrawBuffer) { | 1149 SkASSERT(rt && paint); |
| 1359 return; | 1150 pipelineBuilder->setFromPaint(*paint, rt, clip); |
| 1360 } | |
| 1361 | |
| 1362 if (kDiscard_FlushBit & flagsBitfield) { | |
| 1363 fDrawBuffer->reset(); | |
| 1364 } else { | |
| 1365 fDrawBuffer->flush(); | |
| 1366 } | |
| 1367 fResourceCache->notifyFlushOccurred(); | |
| 1368 fFlushToReduceCacheSize = false; | |
| 1369 } | |
| 1370 | |
| 1371 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes, | |
| 1372 const void* inPixels, size_t outRowBytes, void* outPix els) { | |
| 1373 SkSrcPixelInfo srcPI; | |
| 1374 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL)) { | |
| 1375 return false; | |
| 1376 } | |
| 1377 srcPI.fAlphaType = kUnpremul_SkAlphaType; | |
| 1378 srcPI.fPixels = inPixels; | |
| 1379 srcPI.fRowBytes = inRowBytes; | |
| 1380 | |
| 1381 SkDstPixelInfo dstPI; | |
| 1382 dstPI.fColorType = srcPI.fColorType; | |
| 1383 dstPI.fAlphaType = kPremul_SkAlphaType; | |
| 1384 dstPI.fPixels = outPixels; | |
| 1385 dstPI.fRowBytes = outRowBytes; | |
| 1386 | |
| 1387 return srcPI.convertPixelsTo(&dstPI, width, height); | |
| 1388 } | |
| 1389 | |
| 1390 bool GrContext::writeSurfacePixels(GrSurface* surface, | |
| 1391 int left, int top, int width, int height, | |
| 1392 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes, | |
| 1393 uint32_t pixelOpsFlags) { | |
| 1394 RETURN_FALSE_IF_ABANDONED | |
| 1395 { | |
| 1396 GrTexture* texture = NULL; | |
| 1397 if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asT exture()) && | |
| 1398 fGpu->canWriteTexturePixels(texture, srcConfig)) { | |
| 1399 | |
| 1400 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && | |
| 1401 surface->surfacePriv().hasPendingIO()) { | |
| 1402 this->flush(); | |
| 1403 } | |
| 1404 return fGpu->writeTexturePixels(texture, left, top, width, height, | |
| 1405 srcConfig, buffer, rowBytes); | |
| 1406 // Don't need to check kFlushWrites_PixelOp here, we just did a dire ct write so the | |
| 1407 // upload is already flushed. | |
| 1408 } | |
| 1409 } | |
| 1410 | |
| 1411 // If we didn't do a direct texture write then we upload the pixels to a tex ture and draw. | |
| 1412 GrRenderTarget* renderTarget = surface->asRenderTarget(); | |
| 1413 if (NULL == renderTarget) { | |
| 1414 return false; | |
| 1415 } | |
| 1416 | |
| 1417 // We ignore the preferred config unless it is a R/B swap of the src config. In that case | |
| 1418 // we will upload the original src data to a scratch texture but we will spo of it as the swapped | |
| 1419 // config. This scratch will then have R and B swapped. We correct for this by swapping again | |
| 1420 // when drawing the scratch to the dst using a conversion effect. | |
| 1421 bool swapRAndB = false; | |
| 1422 GrPixelConfig writeConfig = srcConfig; | |
| 1423 if (GrPixelConfigSwapRAndB(srcConfig) == | |
| 1424 fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) { | |
| 1425 writeConfig = GrPixelConfigSwapRAndB(srcConfig); | |
| 1426 swapRAndB = true; | |
| 1427 } | |
| 1428 | |
| 1429 GrSurfaceDesc desc; | |
| 1430 desc.fWidth = width; | |
| 1431 desc.fHeight = height; | |
| 1432 desc.fConfig = writeConfig; | |
| 1433 SkAutoTUnref<GrTexture> texture(this->textureProvider()->refScratchTexture(d esc, | |
| 1434 GrTextureProvider::kApprox_ScratchTexMatch)); | |
| 1435 if (!texture) { | |
| 1436 return false; | |
| 1437 } | |
| 1438 | |
| 1439 SkAutoTUnref<const GrFragmentProcessor> fp; | |
| 1440 SkMatrix textureMatrix; | |
| 1441 textureMatrix.setIDiv(texture->width(), texture->height()); | |
| 1442 | |
| 1443 // allocate a tmp buffer and sw convert the pixels to premul | |
| 1444 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); | |
| 1445 | |
| 1446 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { | |
| 1447 if (!GrPixelConfigIs8888(srcConfig)) { | |
| 1448 return false; | |
| 1449 } | |
| 1450 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); | |
| 1451 // handle the unpremul step on the CPU if we couldn't create an effect t o do it. | |
| 1452 if (NULL == fp) { | |
| 1453 size_t tmpRowBytes = 4 * width; | |
| 1454 tmpPixels.reset(width * height); | |
| 1455 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer , tmpRowBytes, | |
| 1456 tmpPixels.get())) { | |
| 1457 return false; | |
| 1458 } | |
| 1459 rowBytes = tmpRowBytes; | |
| 1460 buffer = tmpPixels.get(); | |
| 1461 } | |
| 1462 } | |
| 1463 if (NULL == fp) { | |
| 1464 fp.reset(GrConfigConversionEffect::Create(texture, | |
| 1465 swapRAndB, | |
| 1466 GrConfigConversionEffect::kNon e_PMConversion, | |
| 1467 textureMatrix)); | |
| 1468 } | |
| 1469 | |
| 1470 // Even if the client told us not to flush, we still flush here. The client may have known that | |
| 1471 // writes to the original surface caused no data hazards, but they can't kno w that the scratch | |
| 1472 // we just got is safe. | |
| 1473 if (texture->surfacePriv().hasPendingIO()) { | |
| 1474 this->flush(); | |
| 1475 } | |
| 1476 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height, | |
| 1477 writeConfig, buffer, rowBytes)) { | |
| 1478 return false; | |
| 1479 } | |
| 1480 | |
| 1481 SkMatrix matrix; | |
| 1482 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); | |
| 1483 | |
| 1484 // This function can be called in the midst of drawing another object (e.g., when uploading a | |
| 1485 // SW-rasterized clip while issuing a draw). So we push the current geometry state before | |
| 1486 // drawing a rect to the render target. | |
| 1487 // The bracket ensures we pop the stack if we wind up flushing below. | |
| 1488 { | |
| 1489 GrDrawTarget* drawTarget = this->prepareToDraw(); | |
| 1490 if (!drawTarget) { | |
| 1491 return false; | |
| 1492 } | |
| 1493 | |
| 1494 GrPipelineBuilder pipelineBuilder; | |
| 1495 pipelineBuilder.addColorProcessor(fp); | |
| 1496 pipelineBuilder.setRenderTarget(renderTarget); | |
| 1497 drawTarget->drawSimpleRect(&pipelineBuilder, | |
| 1498 GrColor_WHITE, | |
| 1499 matrix, | |
| 1500 SkRect::MakeWH(SkIntToScalar(width), SkIntToS calar(height))); | |
| 1501 } | |
| 1502 | |
| 1503 if (kFlushWrites_PixelOp & pixelOpsFlags) { | |
| 1504 this->flushSurfaceWrites(surface); | |
| 1505 } | |
| 1506 | |
| 1507 return true; | 1151 return true; |
| 1508 } | 1152 } |
| 1509 | 1153 |
| 1510 // toggles between RGBA and BGRA | 1154 bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) { |
| 1511 static SkColorType toggle_colortype32(SkColorType ct) { | 1155 RETURN_FALSE_IF_ABANDONED |
| 1512 if (kRGBA_8888_SkColorType == ct) { | |
| 1513 return kBGRA_8888_SkColorType; | |
| 1514 } else { | |
| 1515 SkASSERT(kBGRA_8888_SkColorType == ct); | |
| 1516 return kRGBA_8888_SkColorType; | |
| 1517 } | |
| 1518 } | |
| 1519 | 1156 |
| 1520 bool GrContext::readRenderTargetPixels(GrRenderTarget* target, | 1157 ASSERT_OWNED_RESOURCE(rt); |
| 1521 int left, int top, int width, int height, | 1158 SkASSERT(rt); |
| 1522 GrPixelConfig dstConfig, void* buffer, si ze_t rowBytes, | |
| 1523 uint32_t flags) { | |
| 1524 RETURN_FALSE_IF_ABANDONED | |
| 1525 ASSERT_OWNED_RESOURCE(target); | |
| 1526 SkASSERT(target); | |
| 1527 | |
| 1528 if (!(kDontFlush_PixelOpsFlag & flags) && target->surfacePriv().hasPendingWr ite()) { | |
| 1529 this->flush(); | |
| 1530 } | |
| 1531 | |
| 1532 // Determine which conversions have to be applied: flipY, swapRAnd, and/or u npremul. | |
| 1533 | |
| 1534 // If fGpu->readPixels would incur a y-flip cost then we will read the pixel s upside down. We'll | |
| 1535 // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read. | |
| 1536 bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top, | |
| 1537 width, height, dstConfig, | |
| 1538 rowBytes); | |
| 1539 // We ignore the preferred config if it is different than our config unless it is an R/B swap. | |
| 1540 // In that case we'll perform an R and B swap while drawing to a scratch tex ture of the swapped | |
| 1541 // config. Then we will call readPixels on the scratch with the swapped conf ig. The swaps during | |
| 1542 // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from | |
| 1543 // dstConfig. | |
| 1544 GrPixelConfig readConfig = dstConfig; | |
| 1545 bool swapRAndB = false; | |
| 1546 if (GrPixelConfigSwapRAndB(dstConfig) == | |
| 1547 fGpu->preferredReadPixelsConfig(dstConfig, target->config())) { | |
| 1548 readConfig = GrPixelConfigSwapRAndB(readConfig); | |
| 1549 swapRAndB = true; | |
| 1550 } | |
| 1551 | |
| 1552 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); | |
| 1553 | |
| 1554 if (unpremul && !GrPixelConfigIs8888(dstConfig)) { | |
| 1555 // The unpremul flag is only allowed for these two configs. | |
| 1556 return false; | |
| 1557 } | |
| 1558 | |
| 1559 SkAutoTUnref<GrTexture> tempTexture; | |
| 1560 | |
| 1561 // If the src is a texture and we would have to do conversions after read pi xels, we instead | |
| 1562 // do the conversions by drawing the src to a scratch texture. If we handle any of the | |
| 1563 // conversions in the draw we set the corresponding bool to false so that we don't reapply it | |
| 1564 // on the read back pixels. | |
| 1565 GrTexture* src = target->asTexture(); | |
| 1566 if (src && (swapRAndB || unpremul || flipY)) { | |
| 1567 // Make the scratch a render so we can read its pixels. | |
| 1568 GrSurfaceDesc desc; | |
| 1569 desc.fFlags = kRenderTarget_GrSurfaceFlag; | |
| 1570 desc.fWidth = width; | |
| 1571 desc.fHeight = height; | |
| 1572 desc.fConfig = readConfig; | |
| 1573 desc.fOrigin = kTopLeft_GrSurfaceOrigin; | |
| 1574 | |
| 1575 // When a full read back is faster than a partial we could always make t he scratch exactly | |
| 1576 // match the passed rect. However, if we see many different size rectang les we will trash | |
| 1577 // our texture cache and pay the cost of creating and destroying many te xtures. So, we only | |
| 1578 // request an exact match when the caller is reading an entire RT. | |
| 1579 GrTextureProvider::ScratchTexMatch match = GrTextureProvider::kApprox_Sc ratchTexMatch; | |
| 1580 if (0 == left && | |
| 1581 0 == top && | |
| 1582 target->width() == width && | |
| 1583 target->height() == height && | |
| 1584 fGpu->fullReadPixelsIsFasterThanPartial()) { | |
| 1585 match = GrTextureProvider::kExact_ScratchTexMatch; | |
| 1586 } | |
| 1587 tempTexture.reset(this->textureProvider()->refScratchTexture(desc, match )); | |
| 1588 if (tempTexture) { | |
| 1589 // compute a matrix to perform the draw | |
| 1590 SkMatrix textureMatrix; | |
| 1591 textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top); | |
| 1592 textureMatrix.postIDiv(src->width(), src->height()); | |
| 1593 | |
| 1594 SkAutoTUnref<const GrFragmentProcessor> fp; | |
| 1595 if (unpremul) { | |
| 1596 fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix )); | |
| 1597 if (fp) { | |
| 1598 unpremul = false; // we no longer need to do this on CPU aft er the read back. | |
| 1599 } | |
| 1600 } | |
| 1601 // If we failed to create a PM->UPM effect and have no other convers ions to perform then | |
| 1602 // there is no longer any point to using the scratch. | |
| 1603 if (fp || flipY || swapRAndB) { | |
| 1604 if (!fp) { | |
| 1605 fp.reset(GrConfigConversionEffect::Create( | |
| 1606 src, swapRAndB, GrConfigConversionEffect::kNone_PMCo nversion, | |
| 1607 textureMatrix)); | |
| 1608 } | |
| 1609 swapRAndB = false; // we will handle the swap in the draw. | |
| 1610 | |
| 1611 // We protect the existing geometry here since it may not be | |
| 1612 // clear to the caller that a draw operation (i.e., drawSimpleRe ct) | |
| 1613 // can be invoked in this method | |
| 1614 { | |
| 1615 GrPipelineBuilder pipelineBuilder; | |
| 1616 SkASSERT(fp); | |
| 1617 pipelineBuilder.addColorProcessor(fp); | |
| 1618 | |
| 1619 pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget( )); | |
| 1620 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToSc alar(height)); | |
| 1621 fDrawBuffer->drawSimpleRect(&pipelineBuilder, | |
| 1622 GrColor_WHITE, | |
| 1623 SkMatrix::I(), | |
| 1624 rect); | |
| 1625 // we want to read back from the scratch's origin | |
| 1626 left = 0; | |
| 1627 top = 0; | |
| 1628 target = tempTexture->asRenderTarget(); | |
| 1629 } | |
| 1630 this->flushSurfaceWrites(target); | |
| 1631 } | |
| 1632 } | |
| 1633 } | |
| 1634 | |
| 1635 if (!fGpu->readPixels(target, | |
| 1636 left, top, width, height, | |
| 1637 readConfig, buffer, rowBytes)) { | |
| 1638 return false; | |
| 1639 } | |
| 1640 // Perform any conversions we weren't able to perform using a scratch textur e. | |
| 1641 if (unpremul || swapRAndB) { | |
| 1642 SkDstPixelInfo dstPI; | |
| 1643 if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NUL L)) { | |
| 1644 return false; | |
| 1645 } | |
| 1646 dstPI.fAlphaType = kUnpremul_SkAlphaType; | |
| 1647 dstPI.fPixels = buffer; | |
| 1648 dstPI.fRowBytes = rowBytes; | |
| 1649 | |
| 1650 SkSrcPixelInfo srcPI; | |
| 1651 srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : ds tPI.fColorType; | |
| 1652 srcPI.fAlphaType = kPremul_SkAlphaType; | |
| 1653 srcPI.fPixels = buffer; | |
| 1654 srcPI.fRowBytes = rowBytes; | |
| 1655 | |
| 1656 return srcPI.convertPixelsTo(&dstPI, width, height); | |
| 1657 } | |
| 1658 return true; | 1159 return true; |
| 1659 } | 1160 } |
| 1660 | 1161 |
| 1661 void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) { | |
| 1662 RETURN_IF_ABANDONED | |
| 1663 SkASSERT(surface); | |
| 1664 ASSERT_OWNED_RESOURCE(surface); | |
| 1665 if (surface->surfacePriv().hasPendingIO()) { | |
| 1666 this->flush(); | |
| 1667 } | |
| 1668 GrRenderTarget* rt = surface->asRenderTarget(); | |
| 1669 if (fGpu && rt) { | |
| 1670 fGpu->resolveRenderTarget(rt); | |
| 1671 } | |
| 1672 } | |
| 1673 | |
| 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, | |
| 1687 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) { | |
| 1688 RETURN_IF_ABANDONED | |
| 1689 if (NULL == src || NULL == dst) { | |
| 1690 return; | |
| 1691 } | |
| 1692 ASSERT_OWNED_RESOURCE(src); | |
| 1693 ASSERT_OWNED_RESOURCE(dst); | |
| 1694 | |
| 1695 // Since we're going to the draw target and not GPU, no need to check kNoFlu sh | |
| 1696 // here. | |
| 1697 | |
| 1698 GrDrawTarget* target = this->prepareToDraw(); | |
| 1699 if (NULL == target) { | |
| 1700 return; | |
| 1701 } | |
| 1702 target->copySurface(dst, src, srcRect, dstPoint); | |
| 1703 | |
| 1704 if (kFlushWrites_PixelOp & pixelOpsFlags) { | |
| 1705 this->flush(); | |
| 1706 } | |
| 1707 } | |
| 1708 | |
| 1709 void GrContext::flushSurfaceWrites(GrSurface* surface) { | |
| 1710 RETURN_IF_ABANDONED | |
| 1711 if (surface->surfacePriv().hasPendingWrite()) { | |
| 1712 this->flush(); | |
| 1713 } | |
| 1714 } | |
| 1715 | |
| 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 /* | |
| 1739 * This method finds a path renderer that can draw the specified path on | |
| 1740 * the provided target. | |
| 1741 * Due to its expense, the software path renderer has split out so it can | |
| 1742 * can be individually allowed/disallowed via the "allowSW" boolean. | |
| 1743 */ | |
| 1744 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target, | |
| 1745 const GrPipelineBuilder* pipelineBuil der, | |
| 1746 const SkMatrix& viewMatrix, | |
| 1747 const SkPath& path, | |
| 1748 const GrStrokeInfo& stroke, | |
| 1749 bool allowSW, | |
| 1750 GrPathRendererChain::DrawType drawTyp e, | |
| 1751 GrPathRendererChain::StencilSupport* stencilSupport) { | |
| 1752 | |
| 1753 if (NULL == fPathRendererChain) { | |
| 1754 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this)); | |
| 1755 } | |
| 1756 | |
| 1757 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target, | |
| 1758 pipelineBuilder, | |
| 1759 viewMatrix, | |
| 1760 path, | |
| 1761 stroke, | |
| 1762 drawType, | |
| 1763 stencilSupport); | |
| 1764 | |
| 1765 if (NULL == pr && allowSW) { | |
| 1766 if (NULL == fSoftwarePathRenderer) { | |
| 1767 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this)); | |
| 1768 } | |
| 1769 pr = fSoftwarePathRenderer; | |
| 1770 } | |
| 1771 | |
| 1772 return pr; | |
| 1773 } | |
| 1774 | |
| 1775 //////////////////////////////////////////////////////////////////////////////// | |
| 1776 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const { | |
| 1777 return fGpu->caps()->isConfigRenderable(config, withMSAA); | |
| 1778 } | |
| 1779 | |
| 1780 int GrContext::getRecommendedSampleCount(GrPixelConfig config, | |
| 1781 SkScalar dpi) const { | |
| 1782 if (!this->isConfigRenderable(config, true)) { | |
| 1783 return 0; | |
| 1784 } | |
| 1785 int chosenSampleCount = 0; | |
| 1786 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) { | |
| 1787 if (dpi >= 250.0f) { | |
| 1788 chosenSampleCount = 4; | |
| 1789 } else { | |
| 1790 chosenSampleCount = 16; | |
| 1791 } | |
| 1792 } | |
| 1793 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? | |
| 1794 chosenSampleCount : 0; | |
| 1795 } | |
| 1796 | |
| 1797 GrDrawTarget* GrContext::getTextTarget() { | |
| 1798 return this->prepareToDraw(); | |
| 1799 } | |
| 1800 | |
| 1801 namespace { | |
| 1802 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { | |
| 1803 GrConfigConversionEffect::PMConversion pmToUPM; | |
| 1804 GrConfigConversionEffect::PMConversion upmToPM; | |
| 1805 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upm ToPM); | |
| 1806 *pmToUPMValue = pmToUPM; | |
| 1807 *upmToPMValue = upmToPM; | |
| 1808 } | |
| 1809 } | |
| 1810 | |
| 1811 const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture, | |
| 1812 bool swapRAndB, | |
| 1813 const SkMatrix& matrix ) { | |
| 1814 if (!fDidTestPMConversions) { | |
| 1815 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion); | |
| 1816 fDidTestPMConversions = true; | |
| 1817 } | |
| 1818 GrConfigConversionEffect::PMConversion pmToUPM = | |
| 1819 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion); | |
| 1820 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) { | |
| 1821 return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, mat rix); | |
| 1822 } else { | |
| 1823 return NULL; | |
| 1824 } | |
| 1825 } | |
| 1826 | |
| 1827 const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture, | |
| 1828 bool swapRAndB, | |
| 1829 const SkMatrix& matrix ) { | |
| 1830 if (!fDidTestPMConversions) { | |
| 1831 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion); | |
| 1832 fDidTestPMConversions = true; | |
| 1833 } | |
| 1834 GrConfigConversionEffect::PMConversion upmToPM = | |
| 1835 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion); | |
| 1836 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) { | |
| 1837 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, mat rix); | |
| 1838 } else { | |
| 1839 return NULL; | |
| 1840 } | |
| 1841 } | |
| 1842 | |
| 1843 ////////////////////////////////////////////////////////////////////////////// | |
| 1844 | |
| 1845 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes ) const { | |
| 1846 if (maxTextures) { | |
| 1847 *maxTextures = fResourceCache->getMaxResourceCount(); | |
| 1848 } | |
| 1849 if (maxTextureBytes) { | |
| 1850 *maxTextureBytes = fResourceCache->getMaxResourceBytes(); | |
| 1851 } | |
| 1852 } | |
| 1853 | |
| 1854 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) { | |
| 1855 fResourceCache->setLimits(maxTextures, maxTextureBytes); | |
| 1856 } | |
| 1857 | |
| 1858 ////////////////////////////////////////////////////////////////////////////// | |
| 1859 | |
| 1860 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { | |
| 1861 fGpu->addGpuTraceMarker(marker); | |
| 1862 if (fDrawBuffer) { | |
| 1863 fDrawBuffer->addGpuTraceMarker(marker); | |
| 1864 } | |
| 1865 } | |
| 1866 | |
| 1867 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) { | |
| 1868 fGpu->removeGpuTraceMarker(marker); | |
| 1869 if (fDrawBuffer) { | |
| 1870 fDrawBuffer->removeGpuTraceMarker(marker); | |
| 1871 } | |
| 1872 } | |
| 1873 | |
| 1874 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 1162 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
| 1875 | 1163 |
| 1876 #ifdef GR_TEST_UTILS | 1164 #ifdef GR_TEST_UTILS |
| 1877 | 1165 |
| 1878 BATCH_TEST_DEFINE(StrokeRectBatch) { | 1166 BATCH_TEST_DEFINE(StrokeRectBatch) { |
| 1879 StrokeRectBatch::Geometry geometry; | 1167 StrokeRectBatch::Geometry geometry; |
| 1880 geometry.fViewMatrix = GrTest::TestMatrix(random); | 1168 geometry.fViewMatrix = GrTest::TestMatrix(random); |
| 1881 geometry.fColor = GrRandomColor(random); | 1169 geometry.fColor = GrRandomColor(random); |
| 1882 geometry.fRect = GrTest::TestRect(random); | 1170 geometry.fRect = GrTest::TestRect(random); |
| 1883 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f; | 1171 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f; |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1990 geometry.fColor = GrRandomColor(random); | 1278 geometry.fColor = GrRandomColor(random); |
| 1991 return DrawVerticesBatch::Create(geometry, type, viewMatrix, | 1279 return DrawVerticesBatch::Create(geometry, type, viewMatrix, |
| 1992 positions.begin(), vertexCount, | 1280 positions.begin(), vertexCount, |
| 1993 indices.begin(), hasIndices ? vertexCount : 0, | 1281 indices.begin(), hasIndices ? vertexCount : 0, |
| 1994 colors.begin(), | 1282 colors.begin(), |
| 1995 texCoords.begin(), | 1283 texCoords.begin(), |
| 1996 bounds); | 1284 bounds); |
| 1997 } | 1285 } |
| 1998 | 1286 |
| 1999 #endif | 1287 #endif |
| 1288 | |
| OLD | NEW |